/****************************************************************************
*
*  ALi (Shanghai) Corporation, All Rights Reserved. 2003 Copyright (C)
*
*  File: win_otaupg.c
*
*  Description: 
*              
*  History:
*      Date        	Author             	Version     	Comment
*      ====        	======        	=======   	=======
*
****************************************************************************/
#include <sys_config.h>
#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <bus/dog/dog.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <osal/osal.h>
#ifndef NEW_DEMO_FRAME
#include <api/libpub29/lib_pub27.h>
#include <api/libpub29/lib_as.h>
#endif
#include <api/libota/lib_ota.h>
#include <hld/decv/decv.h>

#include <api/libosd/osd_lib.h>
#include <api/libsi/si_eit.h>
#include <api/libsi/lib_epg.h>
#include <api/libchunk/chunk.h>
#include <hld/sto/sto.h>
#include <hld/sto/sto_dev.h>
#include <api/libchunk/chunk.h>
#include <sys_parameters.h>


#include "osdobjs_def.h"
#include "string.id"
#include "images.id"
#include "osd_config.h"

#include "menus_root.h"
#include "win_com.h"
#include "win_com_popup.h"
#include "win_com_list.h"
#include "win_signalstatus.h"
#ifdef _CAS9_CA_ENABLE_
#include <hld/crypto/crypto.h>
//#include "conax_ap/nn.h"
#endif
#include <api/librsa/flash_cipher.h>
#include <api/librsa/rsa_verify.h>

#ifdef AUTO_OTA
#include <hld/pan/pan_dev.h>
#ifdef AUTO_OTA_DEBUG_PRINTF
#define AUTO_OTA_PRINTF		libc_printf
#else
#define AUTO_OTA_PRINTF(...) 	do{}while(0)
#endif
#endif

#ifdef SUPPORT_CAS_A
#include "win_com_menu_define.h"
#endif

#ifdef _VMX_CA_ENABLE_
#include <api/libcas/vmx/bc_types.h>
#endif

#define C_SECTOR_SIZE       0x10000
#define OTA_PRINTF(...)
//#define OTA_PRINTF libc_printf

#ifndef _USE_32M_MEM_
#ifndef __MM_OTA_UNPRESSED_BOTTOM_ADDR
#define __MM_OTA_UNPRESSED_BOTTOM_ADDR __MM_PVR_VOB_BUFFER_ADDR
#define __MM_OTA_UNPRESSED_LEN       0x600000

#define __MM_OTA_PRESSED_BOTTOM_ADDR (__MM_OTA_UNPRESSED_BOTTOM_ADDR + __MM_OTA_UNPRESSED_LEN)
#define __MM_OTA_PRESSED_LEN         0x400000

#define __MM_OTA_SWAP_BOTTOM_ADDR   (__MM_OTA_PRESSED_BOTTOM_ADDR + __MM_OTA_PRESSED_LEN)
#define __MM_OTA_SWAP_LEN           (256*1024)
#endif
#endif

#define win_ota_upgrade_process_update win_ota_upgrade_process_update_ex 

typedef enum
{
	OTA_STEP_GET_INFO = 0,
	OTA_STEP_DOWNLOADING,
	OTA_STEP_BURNFLASH,	
}OTA_STEP;

UINT32 ota_proc_ret;	/* PROC_SUCCESS / PROC_FAILURE / PROC_STOPPED */
UINT8  ota_user_stop;
OTA_STEP ota_proc_step;
UINT8 *p_otaosd_buff  = NULL;

extern UINT16 ota_pid;

UINT8 ota_loader_exist = 0;
UINT16 ciFlag=0;//add by colin: used for judging wether the third block id(ciplus chunk id) of the flash and the memory is identical

struct dl_info ota_dl_info;
extern OSAL_ID  g_ota_flg_id;
#define OTA_FLAG_PTN    (PROC_SUCCESS | PROC_FAILURE | PROC_STOPPED)
#define OTA_FLAG_TIMEOUT    10

typedef struct
{
	UINT32 compressed_addr;
	UINT32 compressed_len;
	UINT32 uncompressed_addr;
	UINT32 uncompressed_len;
	UINT32 swap_addr;
	UINT32 swap_len;

	UINT32 user_db_start_sector;
	UINT32 user_db_addr;
	UINT32 user_db_addr_offset;
	UINT32 user_db_len;
	UINT32 user_db_sectors;
	
	UINT32 ota_bin_addr;	// ota.bin address, write to userdb as second loader.
	UINT32 ota_bin_size;	// ota.bin size.
	UINT32 ota_bin_sectors;	// ota.bin sectors.
	UINT32 ota_bin_cfg_addr;
	
	UINT32 ota_fw_addr;		// received firmware address.
	UINT32 ota_fw_size; 	// received firmware size.	
	UINT32 ota_upg_addr;	// write to flash address.
	UINT32 ota_upg_size; 	// write to flash size.	
	UINT32 ota_upg_sectors; // write to flash sectors.

	UINT32 backup_db_addr;	// backup current database address
	UINT32 backup_db_size;	// backup current database size;
	UINT32 update_total_sectors;
	UINT32 update_secotrs_index;
#ifdef _VMX_CA_ENABLE_
	UINT32 main_code_addr;
	UINT32 main_code_size;
	UINT32 see_code_addr;
	UINT32 see_code_size;
	UINT32 tmp_buf_addr;
	UINT32 tmp_buf_size;	
#endif
#ifdef _CAS9_CA_ENABLE_
	UINT32 ota_loader_addr;
	UINT32 ota_loader_size;
	UINT32 main_code_addr;
	UINT32 main_code_size;
	UINT32 see_code_addr;
	UINT32 see_code_size;
	
	UINT32 cipher_buf_addr;
	UINT32 cipher_buf_size;	
	UINT32 decrypted_data_addr;
	UINT32 decrypted_data_size;
#endif
}OTA_INFO, *POTA_INFO;

static OTA_INFO m_ota_info;
/*******************************************************************************
* Objects declaration
*******************************************************************************/

extern CONTAINER g_win_otaupg;
	
extern MULTI_TEXT 	otaupg_mtxt_msg;
extern MULTI_TEXT 	otaupg_mtxt_swinfo;
extern TEXT_FIELD 	otaupg_txt_btn;
extern PROGRESS_BAR otaupg_progress_bar;
extern TEXT_FIELD   otaupg_progress_txt;//

static VACTION otaupg_btn_keymap(POBJECT_HEAD pObj, UINT32 key);
static PRESULT otaupg_btn_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2);

static VACTION otaupg_keymap(POBJECT_HEAD pObj, UINT32 key);
static PRESULT otaupg_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2);


#ifdef	_BUILD_OTA_E_
#define WIN_SH_IDX	  	WSTL_WINSEARCH_03_HD
#else
#define WIN_SH_IDX	  	WSTL_WIN_BODYRIGHT_01_HD
#endif


#define MTXT_MSG_SH_IDX		WSTL_TEXT_08_HD
#define MTXT_SWINFO_SH_IDX	WSTL_TEXT_09_HD

#define MTXT_SH_IDX	WSTL_TEXT_08_HD

#define TXT_SH_IDX   WSTL_BUTTON_01_HD
#define TXT_HL_IDX   WSTL_BUTTON_05_HD
#define TXT_SL_IDX   WSTL_BUTTON_01_HD
#define TXT_GRY_IDX  WSTL_BUTTON_07_HD

#define TXT_PERCENT_SH_IDX	WSTL_TEXT_09_HD

#ifndef SD_UI
#ifdef	_BUILD_OTA_E_
#if Maker_GUI_ON
#define	W_W     Maker_GUI_SM_W
#define	W_H     Maker_GUI_SM_H
#define	W_L     Maker_GUI_SM_L
#define	W_T     Maker_GUI_SM_T
#else
#define	W_W     692//493
#define	W_H     488//320
#define	W_L     GET_MID_L(W_W)//60
#define	W_T     98//GET_MID_T(W_H)//60	
#endif
#define MTXT_MSG_L	(W_L + 30)

#define MTXT_MSG_T 	(W_T + 10)
#define MTXT_MSG_W 	(W_W - 60)
#define MTXT_MSG_H 	140

#define BTN_L		(W_L + 200)
#define BTN_T		(MTXT_MSG_T + MTXT_MSG_H + 20)
#define BTN_W		300
#define BTN_H		40

#define MTXT_SWINFO_L	MTXT_MSG_L
#define MTXT_SWINFO_T 	(BTN_T + 60)
#define MTXT_SWINFO_W 	MTXT_MSG_W
#define MTXT_SWINFO_H 	160

#define BAR_L 		(W_L + 100)
#define BAR_T 		(W_T + W_H - 80)
#define BAR_W 		480
#define BAR_H 		24

#define TXTP_L		(BAR_L + BAR_W)
#define TXTP_T 		(BAR_T - 8)
#define TXTP_W 		100 //90
#define TXTP_H 		40

#else
#if Maker_GUI_ON
#ifndef SUPPORT_CAS_A
/* define in win_com_menu_define.h already */
#define	W_L     	Maker_GUI_SM_L
#define	W_T     	Maker_GUI_SM_T
#define	W_W     	Maker_GUI_SM_W
#define	W_H     	Maker_GUI_SM_H
#endif
#else
#ifndef SUPPORT_CAS_A
/* define in win_com_menu_define.h already */
#define	W_L     	248
#define	W_T     	98
#define	W_W     	692
#define	W_H     	488
#endif
#endif

#define MTXT_MSG_L	(W_L + 20)
#define MTXT_MSG_T 	(W_T + 10)
#define MTXT_MSG_W 	(W_W - 40)
#define MTXT_MSG_H 	140

#define BTN_L		(W_L + 120)
#define BTN_T		(MTXT_MSG_T + MTXT_MSG_H + 20)
#define BTN_W		300
#define BTN_H		40

#if Maker_GUI_ON
#define MTXT_SWINFO_L	MTXT_MSG_L
#define MTXT_SWINFO_T 	(BTN_T + 60)
#define MTXT_SWINFO_W 	MTXT_MSG_W
#define MTXT_SWINFO_H 	120
#else
#define MTXT_SWINFO_L	MTXT_MSG_L
#define MTXT_SWINFO_T 	(BTN_T + 60)
#define MTXT_SWINFO_W 	MTXT_MSG_W
#define MTXT_SWINFO_H 	160
#endif

#if Maker_GUI_ON
#define BAR_L 		(W_L + 20)
#define BAR_T 		(W_T + W_H - 80)
#define BAR_W 		480
#define BAR_H 		24
#else
#define BAR_L 		(W_L + 10)
#define BAR_T 		(W_T + W_H - 80)
#define BAR_W 		480
#define BAR_H 		24
#endif

#define TXTP_L		(BAR_L + BAR_W)
#define TXTP_T 		(BAR_T - 8)
#define TXTP_W 		100//sharon 90
#define TXTP_H 		40

#endif
#else
#ifdef	_BUILD_OTA_E_
#define	W_W     482//493
#define	W_H     360//320
#define	W_L     GET_MID_L(W_W)//60
#define	W_T     60//GET_MID_T(W_H)//60	
#define MTXT_MSG_L	(W_L + 30)

#define MTXT_MSG_T 	(W_T + 10)
#define MTXT_MSG_W 	(W_W - 40)
#define MTXT_MSG_H 	90

#define BTN_L		(W_L + 120)
#define BTN_T		(MTXT_MSG_T + MTXT_MSG_H + 20)
#define BTN_W		250
#define BTN_H		30

#define MTXT_SWINFO_L	MTXT_MSG_L
#define MTXT_SWINFO_T 	(BTN_T + 60)
#define MTXT_SWINFO_W 	MTXT_MSG_W
#define MTXT_SWINFO_H 	150

#define BAR_L 		(W_L + 20)
#define BAR_T 		(W_T + W_H - 80)
#define BAR_W 		330
#define BAR_H 		16

#define TXTP_L		(BAR_L + BAR_W)
#define TXTP_T 		(BAR_T - 8)
#define TXTP_W 		90
#define TXTP_H 		30

#else

#define	W_L     	105//384
#define	W_T     	57//138
#define	W_W     	482
#define	W_H     	370

#define MTXT_MSG_L	(W_L + 20)
#define MTXT_MSG_T 	(W_T + 10)
#define MTXT_MSG_W 	(W_W - 40)
#define MTXT_MSG_H 	90

#define BTN_L		(W_L + 120)
#define BTN_T		(MTXT_MSG_T + MTXT_MSG_H + 20)
#define BTN_W		250
#define BTN_H		30

#define MTXT_SWINFO_L	MTXT_MSG_L
#define MTXT_SWINFO_T 	(BTN_T + 60)
#define MTXT_SWINFO_W 	MTXT_MSG_W
#define MTXT_SWINFO_H 	150

#define BAR_L 		(W_L + 20)
#define BAR_T 		(W_T + W_H - 80)
#define BAR_W 		300
#define BAR_H 		16

#define TXTP_L		(BAR_L + BAR_W)
#define TXTP_T 		(BAR_T - 8)
#define TXTP_W 		90//sharon 90
#define TXTP_H 		30
#endif

#endif

#define B_BG_SH_IDX		WSTL_BARBG_01_HD
#define B_MID_SH_IDX	WSTL_NOSHOW_IDX
#define B_SH_IDX		WSTL_BAR_01_HD

#define LDEF_MTXT(root,varMtxt,nextObj,l,t,w,h,sh,cnt,content)	\
	DEF_MULTITEXT(varMtxt,&root,nextObj,C_ATTR_ACTIVE,0, \
    	0,0,0,0,0, l,t,w,h, sh,sh,sh,sh,   \
	    NULL,NULL,  \
    	C_ALIGN_LEFT | C_ALIGN_TOP, cnt,  4,4,w-8,h-8,NULL,content)


#define LDEF_TXT_BTN(root,varTxt,nextObj,ID,IDu,IDd,l,t,w,h,resID)		\
    DEF_TEXTFIELD(varTxt,&root,nextObj,C_ATTR_ACTIVE,0, \
    ID,ID,ID,IDu,IDd, l,t,w,h, TXT_SH_IDX,TXT_HL_IDX,TXT_SL_IDX,TXT_GRY_IDX,   \
    otaupg_btn_keymap,otaupg_btn_callback,  \
    C_ALIGN_CENTER | C_ALIGN_VCENTER, 10,0,resID,NULL)


#if Maker_GUI_OFF
#define LDEF_PROGRESS_BAR(root,varBar,nxtObj,l,t,w,h,style,rl,rt,rw,rh)	\
	DEF_PROGRESSBAR(varBar, &root, nxtObj, C_ATTR_ACTIVE, 0, \
		0, 0, 0, 0, 0, l, t, w, h, B_BG_SH_IDX, B_BG_SH_IDX, B_BG_SH_IDX, B_BG_SH_IDX,\
		NULL, NULL, style, 0, 0, B_MID_SH_IDX, B_SH_IDX, \
		rl,rt , rw, rh, 1, 100, 50, 1)
#else
#define LDEF_PROGRESS_BAR(root,varBar,nxtObj,l,t,w,h,style,rl,rt,rw,rh)	\
	DEF_PROGRESSBAR(varBar, &root, nxtObj, C_ATTR_ACTIVE, 0, \
		0, 0, 0, 0, 0, l, t, w, h, B_BG_SH_IDX, B_BG_SH_IDX, B_BG_SH_IDX, B_BG_SH_IDX,\
		NULL, NULL, style, 0, 0, B_MID_SH_IDX, B_SH_IDX, \
		rl,rt , rw, rh, 1, 100, 100, 1)
#endif		

#define LDEF_TXT_PROGRESS(root,varTxt,nextObj,l,t,w,h,str)		\
    DEF_TEXTFIELD(varTxt,&root,nextObj,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, TXT_PERCENT_SH_IDX,TXT_PERCENT_SH_IDX,TXT_PERCENT_SH_IDX,TXT_PERCENT_SH_IDX,   \
    NULL,NULL,  \
    C_ALIGN_LEFT | C_ALIGN_VCENTER, 10,0,0,str)


#define LDEF_WIN(varCon,nxtObj,l,t,w,h,focusID)		\
    DEF_CONTAINER(varCon,NULL,NULL,C_ATTR_ACTIVE,0, \
    0,0,0,0,0, l,t,w,h, WIN_SH_IDX,WIN_SH_IDX,WIN_SH_IDX,WIN_SH_IDX,   \
    otaupg_keymap,otaupg_callback,  \
    nxtObj, focusID,0)


extern TEXT_CONTENT otamsg_mtxt_content[];
extern TEXT_CONTENT otasw_mtxt_content[];

LDEF_MTXT(g_win_otaupg,otaupg_mtxt_msg,&otaupg_txt_btn,\
	MTXT_MSG_L +230, MTXT_MSG_T, MTXT_MSG_W-230, MTXT_MSG_H,MTXT_MSG_SH_IDX,1,otamsg_mtxt_content)
	
LDEF_TXT_BTN(g_win_otaupg,otaupg_txt_btn,&otaupg_mtxt_swinfo,1,1,1,\
	BTN_L +150 , BTN_T, BTN_W, BTN_H,RS_DISEQC12_MOVEMENT_STOP)

LDEF_MTXT(g_win_otaupg,otaupg_mtxt_swinfo,&otaupg_progress_bar,\
	MTXT_SWINFO_L , MTXT_SWINFO_T, MTXT_SWINFO_W, MTXT_SWINFO_H,MTXT_SWINFO_SH_IDX,3,otasw_mtxt_content)
#ifndef SD_UI
LDEF_PROGRESS_BAR(g_win_otaupg,otaupg_progress_bar,&otaupg_progress_txt,	\
		BAR_L +150 , BAR_T, BAR_W, BAR_H, PROGRESSBAR_HORI_NORMAL | PBAR_STYLE_RECT_STYLE,4,5,BAR_W-8,14)
#else
LDEF_PROGRESS_BAR(g_win_otaupg,otaupg_progress_bar,&otaupg_progress_txt,	\
		BAR_L, BAR_T, BAR_W, BAR_H, PROGRESSBAR_HORI_NORMAL | PBAR_STYLE_RECT_STYLE,2,2,BAR_W-4,12)
#endif
LDEF_TXT_PROGRESS(g_win_otaupg,otaupg_progress_txt, NULL, \
		TXTP_L+150 , TXTP_T, TXTP_W, TXTP_H,display_strs[0])
		
LDEF_WIN(g_win_otaupg,&otaupg_mtxt_msg,W_L,W_T,W_W,W_H,1)

/*******************************************************************************
*	Local functions & variables declare
*******************************************************************************/

TEXT_CONTENT otamsg_mtxt_content[] =
{
	{STRING_ID,0},
};

TEXT_CONTENT otasw_mtxt_content[] =
{
	{STRING_UNICODE,0}, //display_strs[10]
	{STRING_UNICODE,0}, //isplay_strs[11]
	{STRING_UNICODE,0}//display_strs[12]
};

#ifdef SUPPORT_VMX
#define 	OTA_STEP_TIMEOUT	60
#define 	OTA_SEND_KEY_TIME	2
OTA_STEP 	prev_ota_step;
UINT32		gOTACurrentTime=0, gOTAStartTime=0;
BOOL		bSendKey=FALSE;
BOOL		bProcFailureSendKey=FALSE;
#endif

static PRESULT	win_otaupg_message_proc(UINT32 msg_type, UINT32 msg_code);

static INT32 win_otaupg_set_memory(void);
static INT32 win_otaupg_get_info(void);
static INT32 win_otaupg_download(void);
static INT32 win_otaupg_burnflash(void);
static INT32 win_otaupg_reboot(void);

static void win_ota_upgrade_process_update(UINT32 process);
static void win_ota_upgrade_process_update_old(UINT32 process);
static void win_ota_upgrade_process_draw(UINT32 process);
/* 0 - stop , 1 - exit , 2 - download 3 - burnflash 4 - reboot*/
INT32  win_otaup_get_btn_state(void);
static void win_otaup_set_btn_msg_display(BOOL update);
static void win_otaup_set_swinfo_display(BOOL update);
static void win_otaupg_init();
static struct sto_device *m_StoDevice = NULL;


static void StepBurningProgress()
{
    m_ota_info.update_secotrs_index++;	
    win_ota_upgrade_process_update_old((UINT8)(m_ota_info.update_secotrs_index*100/m_ota_info.update_total_sectors));
}

static void change_flash_protect(UINT32 low_addr, UINT32 high_addr)
{
    sto_flash_soft_protect(low_addr, high_addr);
    sflash_soft_protect_init();
}

static INT32 BurnBlock(UINT8 *pBuffer, UINT32 Pos, UINT8 NumSectors)
{
	struct sto_device *sto_dev = m_StoDevice;
    UINT32 param[2];
    INT32 offset, er = SUCCESS;
    UINT8 i;

    for(i=0; i<NumSectors; i++)
    {
        offset = (Pos + i) * C_SECTOR_SIZE;
        param[0] = (UINT32)offset;
        param[1] = C_SECTOR_SIZE >> 10; // length in K bytes
        OTA_PRINTF("%s: erase sector %d\n", __FUNCTION__, Pos+i);
        er = sto_io_control(sto_dev, STO_DRIVER_SECTOR_ERASE_EXT, (UINT32)param);
        if(er != SUCCESS)
        {
            OTA_PRINTF("%s: erase sector %d failed\n", __FUNCTION__, i);
            break;
        }

        if(pBuffer)
        {
            OTA_PRINTF("%s: seek sector %d, offset = %xh\n", __FUNCTION__, Pos+i,offset);
            if(sto_lseek(sto_dev, offset, STO_LSEEK_SET) != offset)
            {
                OTA_PRINTF("%s: seek sector %d failed\n", __FUNCTION__, i);
                er = ERR_FAILED;
                break;
            }

            OTA_PRINTF("%s: write sector %d, src = %xh\n", __FUNCTION__, Pos+i,&pBuffer[C_SECTOR_SIZE * i]);
            if(sto_write(sto_dev, &pBuffer[C_SECTOR_SIZE * i], C_SECTOR_SIZE) != C_SECTOR_SIZE)
            {
                OTA_PRINTF("%s: write sector %d failed\n", __FUNCTION__, i);
                er = ERR_FAILED;
                break;
            }
        }
        
        StepBurningProgress();
    }
    return er;
}

static INT32 InitStorage()
{
    m_StoDevice = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
    if(NULL == m_StoDevice)
    {
        OTA_PRINTF("%s: can not get sto device\n", __FUNCTION__);
        return ERR_NO_DEV;
    }

    INT32 er = sto_open(m_StoDevice);
    if(SUCCESS != er)
    {
        OTA_PRINTF("%s: can not open sto device\n", __FUNCTION__);
    }

	
    return er;
}

static unsigned int get_unzip_size(unsigned char *in)
{
    unsigned int size;
    size = (in[8] << 24) | (in[7] << 16) | (in[6] << 8) | in[5];
    return size;
}

#ifdef _CAS9_CA_ENABLE_
void update_flash_data(UINT32 offset, INT32 len, UINT8 * data)
{
	UINT8 *app_flash_buffer = NULL;
	struct sto_device *flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);

	if(!app_flash_buffer)
		app_flash_buffer = MALLOC(64*1024);

	sto_io_control(flash_dev, STO_DRIVER_SECTOR_BUFFER, (UINT32)app_flash_buffer);
	sto_io_control(flash_dev, STO_DRIVER_SET_FLAG, STO_FLAG_AUTO_ERASE|STO_FLAG_SAVE_REST);
	sto_put_data(flash_dev, (UINT32)offset, data, (INT32)len);

	if(app_flash_buffer)
	{
		FREE(app_flash_buffer);
		app_flash_buffer = NULL;
		sto_io_control(flash_dev, STO_DRIVER_SECTOR_BUFFER, 0);
		sto_io_control(flash_dev, STO_DRIVER_SET_FLAG, 0);
	}
}

#define MAX_CHUNK_NUM		48
#define CHUNK_ARRAY_SIZE	(sizeof(CHUNK_HEADER) * MAX_CHUNK_NUM)

static INT32 ota_cmd_start_resume(UINT32 image_addr, UINT32 image_size)
{
	INT32 ret = 0;
	INT8 i;	
	UINT32 id,mask;
	CHUNK_HEADER *p_m_header, *p_f_header, *p_r_header;
	UINT32 start_addr = 0;
	BOOL compat = TRUE;

	UINT8 m_chk_num;
	UINT8 f_chk_num;
	UINT8 r_chk_num;

	CHUNK_HEADER *m_chkhds = (CHUNK_HEADER *)MALLOC(CHUNK_ARRAY_SIZE);
	CHUNK_HEADER *f_chkhds = (CHUNK_HEADER *)MALLOC(CHUNK_ARRAY_SIZE);
	CHUNK_HEADER *r_chkhds = (CHUNK_HEADER *)MALLOC(CHUNK_ARRAY_SIZE);
	
	chunk_init(image_addr, image_size);

	m_chk_num = chunk_count(0,0);	
	f_chk_num = sto_chunk_count(0,0);

	// memory chunk information
	MEMSET(m_chkhds, 0, CHUNK_ARRAY_SIZE);
	p_m_header = m_chkhds;
	start_addr = 0;
	for(i = 0; i < m_chk_num; i++)
	{
		id = mask = 0;
		
		if(NULL != chunk_goto(&id, mask, i+1))		
		{			
			get_chunk_header(id, p_m_header);

			MEMCPY(p_m_header->reserved, &start_addr, 4);

			start_addr += p_m_header->offset;
		}

		p_m_header++;
	}

	// flash chunk information	
	MEMSET(f_chkhds, 0, sizeof(0));
	p_f_header = f_chkhds;
	start_addr = 0;
	for(i = 0; i < f_chk_num; i++)
	{
		id = mask = 0;
		
		if(ERR_FAILURE != (INT32)sto_chunk_goto(&id, mask, i+1))		
		{
			sto_get_chunk_header(id, p_f_header);
			
			MEMCPY(p_f_header->reserved, &start_addr, 4);
			
			start_addr += p_f_header->offset;
			
		}

		p_f_header++;
	}

	// if memory chunk number is bigger than flash chunk number, then there must be something wrong
	r_chk_num = m_chk_num - f_chk_num;	
	if(f_chk_num < m_chk_num)
	{
		MEMSET(r_chkhds, 0, sizeof(r_chkhds));
		
		p_m_header = m_chkhds;
		p_f_header = f_chkhds;
		for(i = 0; i < f_chk_num; i++)
		{
			if(p_m_header->id == p_f_header->id)
			{
				if(TRUE == compat && p_m_header->offset != p_f_header->offset)
					compat = FALSE;
			}
			else
				break;

			p_m_header++;
			p_f_header++;
		}

		p_r_header = r_chkhds;
		
		if(i == f_chk_num)// IDs of memory and flash chunk list are same.
		{
			if(TRUE == compat)
			{
				for(; i < m_chk_num; i++)
				{
					
					MEMCPY(p_r_header,  p_m_header, sizeof(CHUNK_HEADER));

					MEMCPY((UINT8 *)&start_addr, p_m_header->reserved, 4);
					
					if(sto_fetch_long(start_addr +p_m_header->offset) == (p_m_header+1)->id)//next chunk id is matched with with one chunk link
					{
						//copy header to its target place		
						update_flash_data(start_addr, sizeof(CHUNK_HEADER),(UINT8 *)(image_addr+start_addr));

						if(sto_chunk_count(0,0) == m_chk_num)
						{
							OTA_PRINTF("flash chun list is recovered\n");
							break;
						}
					}

					p_r_header++;
					p_m_header++;
				}
			}
		}
			
	}

	FREE(m_chkhds);
	FREE(f_chkhds);
	FREE(r_chkhds);
	return ret;
}

struct otaupg_ver_info
{
	UINT32 o_f_ver;	// ota loader in flash version
	UINT32 o_m_ver;	// ota loader in memory version
	UINT32 m_f_ver;	// main code in flash version
	UINT32 m_m_ver;	// main code in memory version
	UINT32 s_f_ver;	// see code in flash version
	UINT32 s_m_ver;	// see code in memory version
	UINT32 o_b_ver; // backup ota loader in flash version
};

static INT8 Char2Hex(UINT8 ch)
{
	INT8 ret =  - 1;
	if ((ch <= 0x39) && (ch >= 0x30))
	// '0'~'9'
		ret = ch &0xf;
	else if ((ch <= 102) && (ch >= 97))
	//'a'~'f'
		ret = ch - 97+10;
	else if ((ch <= 70) && (ch >= 65))
	//'A'~'F'
		ret = ch - 65+10;

	return ret;
}

static UINT32 Str2UINT32(UINT8 *str, UINT8 len)
{
	UINT32 ret = 0;
	UINT8 i;
	INT temp;

	if (str == NULL)
		return 0;

	for (i = 0; i < len; i++)
	{
		temp = Char2Hex(*str++);
		if (temp ==  - 1)
			return 0;

		ret = (ret << 4) | temp;
	}

	return ret;
}

#define CODE_LENGTH_OFFSET					0x200	// negative offset from the end of the data
#define CODE_VERSION_OFFSET					0x10	// negative offset from the end of the code
#define CODE_VERSION_LEN					8
#define CODE_VERSION_PADDED_LEN_MIN			0x0
#define CODE_VERSION_PADDED_LEN_MAX			(0x100-1)
#define CODE_APPENDED_LEN					0x300

UINT32 get_code_version(UINT8 *data_addr, UINT32 data_len)
{
	UINT32 code_len;
	UINT32 ver = 0;
	if (0 == Test_RSA_Ram((UINT32)data_addr, data_len))
	{
		code_len = fetch_long(data_addr + data_len - CODE_LENGTH_OFFSET);
		OTA_PRINTF("\tdecrypt_len:0x%08x\n", data_len);
		OTA_PRINTF("\tcode len:0x%08x\n", code_len);

		if ((code_len <= data_len - CODE_APPENDED_LEN - CODE_VERSION_PADDED_LEN_MIN) &&
			(code_len >= data_len - CODE_APPENDED_LEN - CODE_VERSION_PADDED_LEN_MAX))
		{
			ver = Str2UINT32(data_addr + code_len - CODE_VERSION_OFFSET, CODE_VERSION_LEN);
		}
		else
		{
			OTA_PRINTF("Invalid code length!\n");
		}
		OTA_PRINTF("\tcode version: 0x%X\n", ver);
	}
	else
	{
		OTA_PRINTF("\tverify code failed!\n");
	}
	return ver;
}

#define OTA_LOADER_CHUNK_ID		0x00FF0100
#define MAIN_CODE_CHUNK_ID		0x01FE0101
#define SEE_CODE_CHUNK_ID		0x06F90101

#define	DECRPT_KEY_ID			0x22DD0100
#define DECRPT_KEY_MASK 		0xFFFF0000

#define OTA_LOADER_BACKUP_LEN	0xF0000
#define OTA_LOADER_BACKUP_ADDR	(0x800000 - OTA_LOADER_BACKUP_LEN)
	
#define DECRYPT_KEY_BACKUP_LEN	0x10000
#define DECRYPT_KEY_BACKUP_ADDR	(OTA_LOADER_BACKUP_ADDR - DECRYPT_KEY_BACKUP_LEN)

//static R_RSA_PUBLIC_KEY public_key;

static BOOL otaupg_check(struct otaupg_ver_info *ver_info)
{
	struct sto_device *flash_dev = NULL;
	UINT8 *addr;
	UINT32 len;
	UINT32 chunk_id = 0;
	UINT8 *data;
	UINT32 data_len;
	UINT8 key_pos;
	int ret;

	// get unzip size
	m_ota_info.uncompressed_len = (UINT32)get_unzip_size((UINT8 *)m_ota_info.compressed_addr);
	chunk_init(m_ota_info.uncompressed_addr, m_ota_info.uncompressed_len);
#if 1
	// resume chunk list
	ota_cmd_start_resume(m_ota_info.uncompressed_addr, m_ota_info.uncompressed_len);

	// decrypt universal key, fetch public key from flash
#ifdef	_BUILD_OTA_E_
	//because the function of ota_load_parameter will call sto_chunk_init to find ota parameter.
	//so cann't find the key chunk,get the wrong key. 
	flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
	if (flash_dev == NULL)
	{
		OTA_PRINTF("Can't find FLASH device!\n");
	}
	sto_open(flash_dev);
	sto_chunk_init(0, flash_dev->totol_size);
#endif
	
	OTA_PRINTF("fetch public key\n");
	if (decrypt_universal_key(&key_pos, DECRPT_KEY_ID) < 0)
	{
		OTA_PRINTF("Decrypt universal key failed!\n");
		return FALSE;
	}
	
	// be compatible with bootloader check module, move this function call into library
	//fetch_sys_pub_key();

	// get the versions of codes in flash 
	addr = (UINT8 *)m_ota_info.decrypted_data_addr;

#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
	OTA_PRINTF("check ota loader in flash\n");
	len = 0;
	ret = aes_cbc_decrypt_chunk(key_pos, OTA_LOADER_CHUNK_ID, addr, &len);
	if ((ret == 0) && (len != 0))
		ver_info->o_f_ver = get_code_version(addr, len/*, &public_key*/);
#endif

	OTA_PRINTF("check main code in flash\n");
	len = 0;
	ret = aes_cbc_decrypt_chunk(key_pos, MAIN_CODE_CHUNK_ID, addr, &len);
	if ((ret == 0) && (len != 0))
		ver_info->m_f_ver = get_code_version(addr, len/*, &public_key*/);

	OTA_PRINTF("check see code in flash\n");
	len = 0;
	ret = aes_cbc_decrypt_chunk(key_pos, SEE_CODE_CHUNK_ID, addr, &len);
	if ((ret == 0) && (len != 0))
		ver_info->s_f_ver = get_code_version(addr, len/*, &public_key*/);

#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
	// get the version of backup ota loader
	OTA_PRINTF("check backup ota loader in flash\n");
	flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
	if (sto_get_data(flash_dev, (UINT8 *)m_ota_info.cipher_buf_addr,
			OTA_LOADER_BACKUP_ADDR, OTA_LOADER_BACKUP_LEN) == OTA_LOADER_BACKUP_LEN)
	{
		data = (UINT8 *)m_ota_info.cipher_buf_addr;
		if (fetch_long(data + CHUNK_ID) != OTA_LOADER_CHUNK_ID)
		{
			ver_info->o_b_ver = 0; // set to invalid version
		}
		else
		{
			data_len = fetch_long(data + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
			data += CHUNK_HEADER_SIZE;
			if (aes_cbc_decrypt_ram_chunk(key_pos, addr, data, data_len) == 0)
				ver_info->o_b_ver = get_code_version(addr, data_len/*, &public_key*/);
		}
	}
#endif
#else /* only for test */
	// get the versions of codes in memory
	// chunk_init(m_ota_info.uncompressed_addr, m_ota_info.uncompressed_len);

	// get universal key
	UINT8 key_info[65];
	chunk_id = DECRPT_KEY_ID;
	data = chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
	data_len = fetch_long(data + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME; 
	data += CHUNK_HEADER_SIZE;
	MEMCPY(key_info, data, data_len);
	
	// encrypt universal key
	encrypt_universal_key(key_info);

	// decrypt universal key, fetch public key from flash
	decrypt_universal_key(key_info, &key_pos);
	
	addr = (UINT8 *)m_ota_info.uncompressed_addr;
	fetch_pub_key_from_men(addr, &public_key);
	addr = (UINT8 *)m_ota_info.decrypted_data_addr;
#endif

	OTA_PRINTF("check ota loader in memory\n");
#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
	chunk_id = OTA_LOADER_CHUNK_ID;
	m_ota_info.ota_loader_addr = (UINT32)chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
#else
	m_ota_info.ota_loader_addr = m_ota_info.ota_bin_addr;
#endif
	if (m_ota_info.ota_loader_addr)
	{
		data = (UINT8 *)m_ota_info.ota_loader_addr;
		m_ota_info.ota_loader_size = fetch_long(data + CHUNK_OFFSET);
		data_len = fetch_long(data + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
		data += CHUNK_HEADER_SIZE;
		if (aes_cbc_decrypt_ram_chunk(key_pos, addr, data, data_len) == 0)
			ver_info->o_m_ver = get_code_version(addr, data_len/*, &public_key*/);
	}
	OTA_PRINTF("ota loader: 0x%X, 0x%X\n", m_ota_info.ota_loader_addr, m_ota_info.ota_loader_size);

	OTA_PRINTF("check main code in memory\n");
	chunk_id = MAIN_CODE_CHUNK_ID;
	m_ota_info.main_code_addr = (UINT32)chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
	if (m_ota_info.main_code_addr)
	{
		data = (UINT8 *)m_ota_info.main_code_addr;
		m_ota_info.main_code_size = fetch_long(data + CHUNK_OFFSET);
		data_len = fetch_long(data + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
		data += CHUNK_HEADER_SIZE;
		if (aes_cbc_decrypt_ram_chunk(key_pos, addr, data, data_len) == 0)
			ver_info->m_m_ver = get_code_version(addr, data_len/*, &public_key*/);
	}
	OTA_PRINTF("main code: 0x%X, 0x%X\n", m_ota_info.main_code_addr, m_ota_info.main_code_size);

	OTA_PRINTF("check see code in memory\n");
	chunk_id = SEE_CODE_CHUNK_ID;
	m_ota_info.see_code_addr = (UINT32)chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
	if (m_ota_info.see_code_addr)
	{
		data = (UINT8 *)m_ota_info.see_code_addr;
		m_ota_info.see_code_size = fetch_long(data + CHUNK_OFFSET);
		data_len = fetch_long(data + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
		data += CHUNK_HEADER_SIZE;
		if (aes_cbc_decrypt_ram_chunk(key_pos, addr, data, data_len) == 0)
			ver_info->s_m_ver = get_code_version(addr, data_len/*, &public_key*/);
	}
	OTA_PRINTF("see code: 0x%X, 0x%X\n", m_ota_info.see_code_addr, m_ota_info.see_code_size);

	OTA_PRINTF("version info: (0x%X, 0x%X, 0x%X), (0x%X, 0x%X), (0x%X, 0x%X)\n",
		ver_info->o_f_ver, ver_info->o_m_ver, ver_info->o_b_ver, ver_info->m_f_ver,
		ver_info->m_m_ver, ver_info->s_f_ver, ver_info->s_m_ver);

	ce_ioctl((pCE_DEVICE)dev_get_by_id(HLD_DEV_TYPE_CE, 0), IO_CRYPT_POS_SET_IDLE, key_pos);
	return TRUE;
}
#endif /* _CAS9_CA_ENABLE_ */

static BOOL SetupOtaParameters()
{
	UINT32 addr;
	UINT32 len;
	UINT32 bloader_offset;
	UINT32 bl_sector;
	UINT32 bl_count;   //add by colin: used for count the block of ciplus key
	
	// get unzip size;
	m_ota_info.uncompressed_len = (UINT32)get_unzip_size((UINT8 *)m_ota_info.compressed_addr);

	chunk_init(m_ota_info.uncompressed_addr,m_ota_info.uncompressed_len);
	if(!get_chunk_add_len(0x04FB0100, &addr, &len))
		return FALSE;
	m_ota_info.user_db_addr_offset = addr-m_ota_info.uncompressed_addr;
	m_ota_info.user_db_len = len;
	m_ota_info.user_db_start_sector = m_ota_info.user_db_addr_offset/C_SECTOR_SIZE;
	m_ota_info.user_db_sectors = m_ota_info.user_db_len/C_SECTOR_SIZE;

	if(m_ota_info.user_db_len%C_SECTOR_SIZE)
	{
	//	ASSERT(0);
		m_ota_info.user_db_sectors++;
	}
	// find the firmware position	
	m_ota_info.ota_fw_addr = m_ota_info.uncompressed_addr;
	m_ota_info.ota_fw_size = addr + len - m_ota_info.ota_fw_addr;
		
	// find ota.bin position.
	m_ota_info.ota_bin_addr = m_ota_info.ota_fw_addr + m_ota_info.ota_fw_size;
	m_ota_info.ota_bin_size = m_ota_info.uncompressed_len - m_ota_info.ota_fw_size;
	m_ota_info.ota_bin_sectors = m_ota_info.ota_bin_size/C_SECTOR_SIZE;
	if(m_ota_info.ota_bin_size % C_SECTOR_SIZE)
		m_ota_info.ota_bin_sectors++;

#if (!defined(_VMX_CA_ENABLE_))&&(!defined(_CAS9_CA_ENABLE_) ||(!defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)))
	// calculate upgrade sectors.
	bloader_offset = ((UINT32)(*((UINT8 *)m_ota_info.ota_fw_addr+8)) << 24) | ((UINT32)(*((UINT8 *)m_ota_info.ota_fw_addr + 9)) << 16) \
		| ((UINT32)(*((UINT8 *)m_ota_info.ota_fw_addr + 10)) << 8) | ((UINT32)(*((UINT8 *)m_ota_info.ota_fw_addr + 11)) << 0);
	bl_sector = bloader_offset / C_SECTOR_SIZE;
	if (0 != bloader_offset % C_SECTOR_SIZE)
	bl_sector ++;	//  Colin>>This sentence has already skipped the HDCP key
	if (ciFlag)
		{
			 bl_count=0x20000/C_SECTOR_SIZE;
			 if (0 != 0x20000 % C_SECTOR_SIZE)
		      	        bl_count++;
			 bl_sector+=bl_count;
		}
      
	m_ota_info.ota_upg_addr = m_ota_info.ota_fw_addr + bl_sector * C_SECTOR_SIZE; //skip bootloader, hdcp, (and ciplus sector.)
	m_ota_info.ota_upg_size = m_ota_info.ota_fw_size - len - bl_sector * C_SECTOR_SIZE;	//skip bootloader and user_db
	m_ota_info.ota_upg_sectors = m_ota_info.ota_upg_size/C_SECTOR_SIZE;
	if(m_ota_info.ota_upg_size % C_SECTOR_SIZE)
		m_ota_info.ota_upg_sectors++;

	
	m_ota_info.update_secotrs_index = 0;
#ifdef _BUILD_OTA_E_
	m_ota_info.update_total_sectors = m_ota_info.ota_upg_sectors + \
		m_ota_info.user_db_sectors;
#else
	m_ota_info.update_total_sectors = m_ota_info.ota_upg_sectors + \
		m_ota_info.ota_bin_sectors + m_ota_info.user_db_sectors;
#endif

#endif

	// find ota_cfg chunk.
	chunk_init(m_ota_info.ota_bin_addr,m_ota_info.ota_bin_size);
	UINT32 chid = 0x11EE0200;
	UINT8 *p = (UINT8*)chunk_goto(&chid, 0xFFFFFFFF, 1);
	if(p)
	{
		m_ota_info.ota_bin_cfg_addr = (UINT32)p;
		ota_save_parameter(p);
	}
	return TRUE;
}

static INT32 BackupDatabase()
{
	struct sto_device *sto_dev = m_StoDevice;
    INT32 er;

	if(sto_lseek(sto_dev, (INT32)m_ota_info.user_db_addr_offset, STO_LSEEK_SET) !=  (INT32)m_ota_info.user_db_addr_offset)
        return ERR_FAILED;
	if(sto_read(sto_dev, (UINT8 *)m_ota_info.backup_db_addr, (INT32)m_ota_info.user_db_len) != (INT32)m_ota_info.user_db_len)
        return ERR_FAILED;
    return SUCCESS;
}

//Bool_flash_mem(): add by colin to judge wether the third block id(ciplus chunk id) of the flash and the memory is identical
UINT16 Bool_flash_mem()
{
	  UINT16 flag;
    UINT8 * addr;
	  UINT32 bl_sector;
	  UINT32 offset ;
	  //struct sto_device *flash_dev;
	  UINT32 ci_chid;  //add by colin:used for restore the ciplus chunk_id
	  UINT32 *pCiplus;   //add by colin:used for reading the ciplus chunk_id
	  unsigned char *data; 
    addr = (UINT8 *)SYS_FLASH_BASE_ADDR;
	  offset = ((UINT32)(*(addr + 8)) << 24) | ((UINT32)(*(addr + 9)) << 16) \
			| ((UINT32)(*(addr + 10)) << 8) | ((UINT32)(*(addr + 11)) << 0);
           bl_sector = offset / C_SECTOR_SIZE;
	   if (0 != offset % C_SECTOR_SIZE)
		bl_sector ++;  
	   addr = addr+bl_sector *C_SECTOR_SIZE;
           pCiplus = (UINT32 *)addr;
	  data = (unsigned char *)pCiplus;
          ci_chid = fetch_long(data + CHUNK_ID);
	  libc_printf("ci's chunk id is %d",ci_chid);
	   if(ci_chid==0x09F60101)
		  flag=1;
	   else 
		  flag=0;
	   libc_printf("ciFlag is %d\n",flag);	
	   return flag;
	      
}
static INT32 BurnFlash()
{
    INT32 er;
	UINT32 offset;
	UINT32 bl_sector;
	UINT32 bl_count;   //add by colin :used for count the block number of ciplus key
	UINT8 * addr;

    sys_data_set_factory_reset(TRUE);
    sys_data_save(0);
    ge_io_ctrl(g_ge_dev, GE_IO_SET_SYNC_MODE, GE_SYNC_MODE_POOLING);
    osal_task_dispatch_off();
    //osal_interrupt_disable();
    do
    {
		addr = (UINT8 *)SYS_FLASH_BASE_ADDR;
		offset = ((UINT32)(*(addr + 8)) << 24) | ((UINT32)(*(addr + 9)) << 16) \
			| ((UINT32)(*(addr + 10)) << 8) | ((UINT32)(*(addr + 11)) << 0);
		bl_sector = offset / C_SECTOR_SIZE;
		if (0 != offset % C_SECTOR_SIZE)
		bl_sector ++;  //  Colin>>This sentence has already skipped the HDCP key
		
		if(ciFlag) //Colin>>this "if...else.." is used for compatible because we changed the block scripts
			{
				//skip ciplus   add by colin
				addr=addr+bl_sector *C_SECTOR_SIZE;
				offset = ((UINT32)(*(addr + 8)) << 24) | ((UINT32)(*(addr + 9)) << 16) \
					| ((UINT32)(*(addr + 10)) << 8) | ((UINT32)(*(addr + 11)) << 0);
				bl_count= offset / C_SECTOR_SIZE;
				if (0 != offset % C_SECTOR_SIZE)
		      	        	bl_count++;
				bl_sector+=bl_count;
				//end skip ciplus add by colin
			}
		
#ifndef _BUILD_OTA_E_

#ifdef BACKUP_TEMP_INFO
        save_swap_data(&system_config,sizeof(system_config));
#endif
        er = BackupDatabase();
        if(SUCCESS != er)
            break;

		// burn ota.bin
        //change_flash_protect(C_OTACODE_OFFSET, C_OTACODE_OFFSET+C_OTACODE_SIZE);
        er = BurnBlock((UINT8*)m_ota_info.ota_bin_addr, m_ota_info.user_db_start_sector , m_ota_info.ota_bin_sectors);
        if(SUCCESS != er)
            break;

		// burn firmware.bin
        //change_flash_protect(C_MAINCODE_OFFSET, C_MAINCODE_OFFSET+C_MAINCODE_SIZE);
        er = BurnBlock((UINT8*)m_ota_info.ota_upg_addr, bl_sector, m_ota_info.ota_upg_sectors);
        if(SUCCESS != er)
            break;

        //change_flash_protect(C_DATABASE_OFFSET, C_DATABASE_OFFSET+C_DATABASE_SIZE);
        er = BurnBlock((UINT8*)m_ota_info.backup_db_addr, m_ota_info.user_db_start_sector, m_ota_info.user_db_sectors);
        if(SUCCESS != er)
            break;
#else
        er = BurnBlock((UINT8*)m_ota_info.ota_upg_addr, bl_sector, m_ota_info.ota_upg_sectors);
        if(SUCCESS != er)
            break;

        //UpdateMessage("Restore database...");
		er = BurnBlock((UINT8*)NULL, m_ota_info.user_db_start_sector, m_ota_info.user_db_sectors);
		if(SUCCESS != er)
		    break;
#endif
    }while(0);
    //osal_interrupt_enable();
    osal_task_dispatch_on();
    ge_io_ctrl(g_ge_dev, GE_IO_SET_SYNC_MODE, GE_SYNC_MODE_INTERRUPT);
    sys_data_set_factory_reset(FALSE);
    sys_data_save(0);
    return er;
}

/*******************************************************************************
*	Window's keymap, proc and  callback
*******************************************************************************/

static VACTION otaupg_btn_keymap(POBJECT_HEAD pObj, UINT32 key)
{
	VACTION act;
	
    switch(key)
    {
    case V_KEY_ENTER:
        #ifdef NEW_MANUAL_OTA 
		if (ota_proc_step == OTA_STEP_DOWNLOADING && ota_proc_ret != PROC_SUCCESS)
			act = VACT_PASS;
		else
        act = VACT_ENTER;
		#else
		act = VACT_ENTER;
		#endif
		break;
    default:
        act = VACT_PASS;
    }

	return act;
}


static PRESULT otaupg_btn_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	PRESULT ret = PROC_PASS;
	VACTION unact;
	UINT8 back_saved;
	INT32 btn_state;
	win_popup_choice_t choice;
	lpVSCR apvscr;

	#ifdef _VMX_CA_ENABLE_
		TEXT_FIELD* txt_btn = &otaupg_txt_btn;	
	#endif

	switch(event)
	{
	case EVN_UNKNOWN_ACTION:
		unact = (VACTION)(param1>>16);
		if(unact == VACT_ENTER)
		{
			/* 0 - stop , 1 - exit , 2 - download 3 - burnflash 4 - reboot*/
			btn_state = win_otaup_get_btn_state();
			apvscr = OSD_GetTaskVscr(osal_task_get_current_id());
			switch(btn_state)
			{
			case 0:
				if(!ota_user_stop)
				{
					ota_stop_service();
					ota_user_stop = 1;					
				}
				break;
			case 1:
				ret = PROC_LEAVE;
				break;
			case 2:
				win_otaupg_download();
				win_otaup_set_btn_msg_display(TRUE);
				OSD_UpdateVscr(apvscr);
				break;
			case 3:
			#if (!defined(_BUILD_OTA_E_) && !defined(_CAS9_CA_ENABLE_) && !defined(NEW_MANUAL_OTA) && !defined(_VMX_CA_ENABLE_))
				win_compopup_init(WIN_POPUP_TYPE_OKNO);
				win_compopup_set_msg("Are you sure to burn the flash?", NULL, 0);
				win_compopup_set_default_choice(WIN_POP_CHOICE_NO);
				choice = win_compopup_open_ext(&back_saved);
				//win_compopup_smsg_restoreback();
				if(choice == WIN_POP_CHOICE_YES)
			#endif
				{
				#ifdef _VMX_CA_ENABLE_
					OSD_SetTextFieldContent(txt_btn, STRING_ID, RS_OTA_BURNFLASH);
					OSD_TrackObject( (POBJECT_HEAD)txt_btn, C_UPDATE_ALL);	
				#endif					

					if (0 != win_otaupg_burnflash())
					{
						ota_proc_ret = PROC_FAILURE;
                        ret = PROC_LEAVE;
                        break;
                    }
					win_otaup_set_btn_msg_display(TRUE);
					OSD_UpdateVscr(apvscr);
				}
				break;
			case 4:
				win_otaupg_reboot();
				break;
			}
		}
		break;
	}

	return ret;
}


static VACTION otaupg_keymap(POBJECT_HEAD pObj, UINT32 key)
{
	VACTION act;
	
    switch(key)
    {
    case V_KEY_MENU:
    case V_KEY_EXIT:
        act = VACT_CLOSE;
        break;
    case V_KEY_POWER:
        act = VACT_PASS + 1;
        break;
    default:
        act = VACT_PASS;
    }

	return act;
}

//extern void ap_send_epg_PF_update();
//extern void ap_send_epg_sch_update();
//extern void ap_send_epg_detail_update();
extern void ap_epg_call_back(UINT32 tp_id, UINT16 service_id, UINT8 event_type);

static PRESULT otaupg_callback(POBJECT_HEAD pObj, VEVENT event, UINT32 param1, UINT32 param2)
{
	PRESULT ret = PROC_PASS;
	CONTAINER* cont = (CONTAINER*)pObj;
	INT32 btn_state;
	UINT8 back_saved;
	
	UINT8	id = OSD_GetObjID(pObj);
	

	switch(event)
	{
	case EVN_PRE_OPEN:
        system_state = SYS_STATE_OTA_UPG;
		//p_otaosd_buff = MALLOC(OSD_VSRC_MEM_MAX_SIZE);
#ifndef _BUILD_OTA_E_
		epg_release();
#endif
		if(win_otaupg_set_memory() != 0)
		{
			win_compopup_init(WIN_POPUP_TYPE_OK);
			win_compopup_set_msg("No Enough memory!", NULL, 0);
			win_compopup_open_ext(& back_saved);
			return PROC_LEAVE;
		}
#ifdef SUPPORT_CAS9
		#ifdef MULTI_DESCRAMBLE
        UINT8 i = 0;
        for(i = 0;i < 3;i++)  //stop filter all the TP
        {
            api_mcas_stop_transponder_multi_des(i);
        }
        #else
			api_mcas_stop_transponder();
        #endif
#endif		
#ifdef SUPPORT_VMX
        UINT8 i = 0;
        for(i = 0; i < 3; i++)  //stop filter all the TP
        {
            api_mcas_stop_transponder_multi_des(i);
        }
		vmx_cas_run_bc_task(FALSE);
#endif

		wincom_open_title((POBJECT_HEAD)&g_win_otaupg,RS_TOOLS_SW_UPGRADE_BY_OTA, 0);
		win_otaupg_get_info();
		win_otaup_set_btn_msg_display(FALSE);
		win_otaup_set_swinfo_display(FALSE);
		win_otaupg_init();
#ifdef SUPPORT_VMX  
		prev_ota_step=OTA_STEP_BURNFLASH+1;
#endif
		break;
		
	case EVN_POST_OPEN:
		break;
	
	case EVN_PRE_CLOSE:
        if(ota_proc_step == OTA_STEP_BURNFLASH && ota_proc_ret != PROC_FAILURE)
        {
            ret = PROC_LOOP;
            break;
        }
        else
        {
            //btn_state = win_otaup_get_btn_state();
            if(ota_proc_ret == 0)
            {
                ota_stop_service();
				//ota_user_stop = 1;
            }
        }
  /*          
		if(btn_state == 0)
		{
			if(!ota_user_stop)
			{
				ota_stop_service();
				ota_user_stop = 1;					
			}
		}
		
		if(btn_state != 1)
			ret = PROC_LOOP;
*/
		/* Make OSD not flickering */
		*((UINT32*)param2) &= ~C_CLOSE_CLRBACK_FLG;	
		
		break;

	case EVN_POST_CLOSE:
		if(p_otaosd_buff != NULL)
		{
			OSD_TaskBuffer_Free(OSAL_INVALID_ID,p_otaosd_buff);
			//FREE(p_otaosd_buff);
			//p_otaosd_buff = NULL;
		}
#ifndef _BUILD_OTA_E_
    	epg_init(SIE_EIT_WHOLE_TP, (UINT8*)__MM_EPG_BUFFER_START/*buffer*/, __MM_EPG_BUFFER_LEN, ap_epg_call_back);
#endif
#ifdef SUPPORT_CAS9
        #ifdef MULTI_DESCRAMBLE
        api_mcas_start_transponder_multi_des(0);//ts_route.dmx_id-1);
        #else
	    api_mcas_start_transponder();
        #endif
#endif
#ifdef SUPPORT_VMX
	api_mcas_start_transponder_multi_des(0);
	vmx_cas_run_bc_task(TRUE);
#endif
#if defined(_S3281_) && defined(_USE_32M_MEM_) || defined(_M3383_SABBAT_)
		nim_open((struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_NIM, 0));
		dmx_start((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
		dmx_start((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 1));
#endif
		
		system_state = SYS_STATE_NORMAL;
		break;
    case EVN_UNKNOWN_ACTION:
        ret = PROC_LOOP;
		break;
	case EVN_MSG_GOT:
		ret = win_otaupg_message_proc(param1,param2);
		break;
	}
	return ret;
}


static PRESULT	win_otaupg_message_proc(UINT32 msg_type, UINT32 msg_code)
{
	PRESULT ret = PROC_PASS;
    UINT flgptn = 0;
	


    if( msg_type == CTRL_MSG_SUBTYPE_STATUS_OTA_PROCESS_MSG)
    { 
        win_ota_upgrade_process_draw(msg_code);
    }

    
	if(ret == PROC_PASS && ota_proc_ret==0)
	{
		osal_flag_wait(&flgptn,g_ota_flg_id, OTA_FLAG_PTN, OSAL_TWF_ORW, OTA_FLAG_TIMEOUT);

		switch(ota_proc_step)
		{
		case OTA_STEP_GET_INFO:
 		case OTA_STEP_DOWNLOADING:		
	        if(ota_user_stop &&  (flgptn & PROC_STOPPED ) )
	            ota_proc_ret = PROC_STOPPED;
			
	        if(!ota_user_stop && (flgptn & PROC_FAILURE) )
	            ota_proc_ret = PROC_FAILURE;
			
	        if(flgptn & PROC_SUCCESS)
	        {
	            if(ota_user_stop)   
	               ota_proc_ret = PROC_STOPPED;
	            else
	               ota_proc_ret = PROC_SUCCESS;
	        }
			break;
			
		case OTA_STEP_BURNFLASH:
			if(flgptn & PROC_FAILURE)
				ota_proc_ret = PROC_FAILURE;
			if(flgptn & PROC_SUCCESS)
				ota_proc_ret = PROC_SUCCESS;
			break;
		
		}

		if(ota_proc_ret!= 0)
		{
			win_otaup_set_btn_msg_display(TRUE);	
			if(ota_proc_step == OTA_STEP_GET_INFO)
				win_otaup_set_swinfo_display(TRUE);
			#ifdef NEW_MANUAL_OTA
		   	if (ota_proc_step == OTA_STEP_BURNFLASH && ota_proc_ret == PROC_SUCCESS)
            {
                osal_task_sleep(5000);
            }
            ap_send_key(V_KEY_ENTER, TRUE);
			#endif
		}
	}
#ifdef SUPPORT_VMX
	if(FALSE==api_osm_get_confirm())
	{
		UINT32 hkey;
		
		if(prev_ota_step!=ota_proc_step)
		{
			gOTAStartTime=osal_get_time();
			prev_ota_step=ota_proc_step;
			bSendKey=FALSE;
		}
		gOTACurrentTime=osal_get_time();

		if(ota_proc_step==OTA_STEP_GET_INFO)
		{
			if((gOTACurrentTime-gOTAStartTime > OTA_STEP_TIMEOUT)&&(bSendKey==FALSE))
			{
				libc_printf("[!] OTA_STEP_TIMEOUT(%d) occurs!!\n", OTA_STEP_TIMEOUT);
				
			    ap_vk_to_hk(0, V_KEY_EXIT, &hkey);
			    ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
				bSendKey=TRUE;
			}	

			if(ota_proc_ret == PROC_SUCCESS&&(bSendKey==FALSE))
			{
				if(gOTACurrentTime-gOTAStartTime > OTA_SEND_KEY_TIME)
				{
					libc_printf("-OTA_STEP_GET_INFO(PROC_SUCCESS)\n");
					ap_vk_to_hk(0, V_KEY_ENTER, &hkey);
				    ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
					bSendKey=TRUE;
				}
			}		
		}	
		else if(ota_proc_step==OTA_STEP_DOWNLOADING)
		{
			if(ota_proc_ret == PROC_SUCCESS&&(bSendKey==FALSE))
			{
				if(gOTACurrentTime-gOTAStartTime > OTA_SEND_KEY_TIME)
				{
					libc_printf("-OTA_STEP_DOWNLOADING(PROC_SUCCESS)\n");
					ap_vk_to_hk(0, V_KEY_ENTER, &hkey);
				    ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
					bSendKey=TRUE;
				}
			}	
			else if(ota_proc_ret == PROC_FAILURE&&(bSendKey==FALSE))
			{
				if(bProcFailureSendKey==FALSE)
				{
					//ready for send exit key
					libc_printf("-OTA_STEP_DOWNLOADING(PROC_FAILURE):ready for send exit key\n");
					gOTAStartTime=osal_get_time();
					bProcFailureSendKey=TRUE;
				}
				else
				{
					if(gOTACurrentTime-gOTAStartTime > OTA_SEND_KEY_TIME)
					{
						libc_printf("-OTA_STEP_DOWNLOADING(PROC_FAILURE)\n");
						ap_vk_to_hk(0, V_KEY_EXIT, &hkey);
					    ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
						bSendKey=TRUE;
					}
				}
			}
		}
		else if(ota_proc_step==OTA_STEP_BURNFLASH)
		{
			if(ota_proc_ret == PROC_SUCCESS&&(bSendKey==FALSE))
			{
				libc_printf("-OTA_STEP_BURNFLASH(PROC_SUCCESS)\n");
				ap_vk_to_hk(0, V_KEY_ENTER, &hkey);
				ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
				bSendKey=TRUE;
			}	
			else if(ota_proc_ret == PROC_FAILURE&&(bSendKey==FALSE))
			{
				if(bProcFailureSendKey==FALSE)
				{
					//ready for send exit key
					libc_printf("-OTA_STEP_BURNFLASH(PROC_FAILURE):ready for send exit key\n");
					gOTAStartTime=osal_get_time();
					bProcFailureSendKey=TRUE;
				}
				else
				{
					if(gOTACurrentTime-gOTAStartTime > OTA_SEND_KEY_TIME)
					{
						libc_printf("-OTA_STEP_BURNFLASH(PROC_SUCCESS)\n");
						ap_vk_to_hk(0, V_KEY_EXIT, &hkey);
						ap_send_msg(CTRL_MSG_SUBTYPE_KEY, hkey, TRUE);
						bSendKey=TRUE;
					}
				}
			}
		}
	}
#endif

	return ret;
}

#if (defined(_BUILD_OTA_E_))
static UINT32 g_ota_addr = 0;
static UINT8 find_ota_loader()
{
	#define C_SECTOR_SIZE   0x10000
	
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;
	
	struct sto_device *flash_dev;

	if ((flash_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0)) == NULL)
	{
		return 0;
	}
	
    while(pointer < flash_dev->totol_size)
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);
        if(data_len && (data_len < data_off) && (data_crc != NO_CRC) && ((data_id & CHUNKID_SECLOADER_MASK) == CHUNKID_SECLOADER))
        {
            buffer = (UINT8 *)MALLOC(data_len);
        	if(buffer != NULL)
        	{
    		    sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
                if(data_crc == crc)
                {
                    g_ota_addr = pointer;
                    return 1;
                }
        	}
        }
	    pointer += C_SECTOR_SIZE;
    }
    return 0;
}
#endif




static INT32 win_otaupg_set_memory(void)
{
	UINT32 addr_offset, len;
	#ifndef _USE_32M_MEM_
	#ifdef _M3383_SABBAT_
	//__MM_DMX_AVP_START_ADDR is low address. followed by  __MM_PVR_VOB_BUFFER_ADDR.
	//because we use dmx buffer,so after downloading,we must stop dmx.
	m_ota_info.uncompressed_addr =__MM_DMX_AVP_START_ADDR;//= // __MM_PVR_VOB_BUFFER_ADDR + 0x250000;
	m_ota_info.uncompressed_len = 0x520000; //0x500000
	m_ota_info.compressed_addr = __MM_PVR_VOB_BUFFER_ADDR+0x400000;//m_ota_info.uncompressed_addr+m_ota_info.uncompressed_len;
	m_ota_info.compressed_len = 0x340000;//0x200000;
	m_ota_info.swap_addr = m_ota_info.compressed_addr + m_ota_info.compressed_len;
	m_ota_info.swap_len = 256*1024;
	m_ota_info.backup_db_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr+m_ota_info.swap_len;
	m_ota_info.backup_db_size = 0x200000;
	#else
    //#ifdef _SUPPORT_64M_MEM_MINI
	//m_ota_info.uncompressed_addr = __MM_PVR_VOB_BUFFER_ADDR + 0x100000; //adjust 1M avoid ota download write FB buffer
    //#else
    m_ota_info.uncompressed_addr = __MM_OTA_UNPRESSED_BOTTOM_ADDR;//__MM_PVR_VOB_BUFFER_ADDR;
    //#endif
	m_ota_info.uncompressed_len = __MM_OTA_UNPRESSED_LEN;//0x600000; //0x500000
	m_ota_info.compressed_addr = __MM_OTA_PRESSED_BOTTOM_ADDR;//m_ota_info.uncompressed_addr+m_ota_info.uncompressed_len;
	m_ota_info.compressed_len = __MM_OTA_PRESSED_LEN;//0x400000;//0x200000;
	m_ota_info.swap_addr = __MM_OTA_SWAP_BOTTOM_ADDR;//m_ota_info.compressed_addr + m_ota_info.compressed_len;
	m_ota_info.swap_len = __MM_OTA_SWAP_LEN;//256*1024;
	m_ota_info.backup_db_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr+m_ota_info.swap_len;
	m_ota_info.backup_db_size = 0x200000;
	#endif
	#else
	m_ota_info.uncompressed_addr = __MM_NIM_BUFFER_ADDR;
	#ifdef _VMX_CA_ENABLE_
	m_ota_info.uncompressed_len = 0x520000; //0x500000
	#else
	m_ota_info.uncompressed_len = 0x500000; //0x500000
	#endif
	m_ota_info.compressed_addr = m_ota_info.uncompressed_addr+m_ota_info.uncompressed_len;
	m_ota_info.compressed_len = 0x300000;//0x200000;
	m_ota_info.swap_addr = m_ota_info.compressed_addr + m_ota_info.compressed_len;
	m_ota_info.swap_len = 256*1024;
	m_ota_info.backup_db_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr+m_ota_info.swap_len;
	m_ota_info.backup_db_size = 0x200000;
	#endif

	
	p_otaosd_buff = (UINT8 *)((m_ota_info.backup_db_addr+m_ota_info.backup_db_size)|0xa0000000);
	
	ota_mem_config(
		m_ota_info.compressed_addr,
		m_ota_info.compressed_len,
		m_ota_info.uncompressed_addr,
		m_ota_info.uncompressed_len,
		m_ota_info.swap_addr,
		m_ota_info.swap_len);
#ifdef _VMX_CA_ENABLE_
		m_ota_info.tmp_buf_addr=m_ota_info.compressed_addr;
		m_ota_info.tmp_buf_size=0x200000;
#endif

#ifdef _CAS9_CA_ENABLE_
	#ifndef _USE_32M_MEM_	
	#ifdef _M3383_SABBAT_
	// when start Decrypt/Signatur Test, compressed_addr could be re-used!!!
	m_ota_info.cipher_buf_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr + m_ota_info.swap_len;
	m_ota_info.cipher_buf_size = 0x1A0000;//=compressed_len/2
	m_ota_info.decrypted_data_addr = m_ota_info.cipher_buf_addr + m_ota_info.cipher_buf_size;
	m_ota_info.decrypted_data_size = 0x1A0000;
	flash_cipher_buf_init((UINT8 *)m_ota_info.cipher_buf_addr, m_ota_info.cipher_buf_size);
	#else
	// when start Decrypt/Signatur Test, compressed_addr could be re-used!!!
	m_ota_info.cipher_buf_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr + m_ota_info.swap_len;
	m_ota_info.cipher_buf_size = 0x200000;
	m_ota_info.decrypted_data_addr = m_ota_info.cipher_buf_addr + m_ota_info.cipher_buf_size;
	m_ota_info.decrypted_data_size = 0x200000;
	flash_cipher_buf_init((UINT8 *)m_ota_info.cipher_buf_addr, m_ota_info.cipher_buf_size);
	#endif
	#else
	// when start Decrypt/Signatur Test, compressed_addr could be re-used!!!
	m_ota_info.cipher_buf_addr = m_ota_info.compressed_addr;//m_ota_info.swap_addr + m_ota_info.swap_len;
	m_ota_info.cipher_buf_size = 0x150000;
	m_ota_info.decrypted_data_addr = m_ota_info.cipher_buf_addr + m_ota_info.cipher_buf_size;
	m_ota_info.decrypted_data_size = 0x150000;
	flash_cipher_buf_init((UINT8 *)m_ota_info.cipher_buf_addr, m_ota_info.cipher_buf_size);
	#endif
#endif
	return 0;
}


static INT32 win_otaupg_get_info(void)
{
	ota_proc_ret 	  = 0;
	ota_user_stop  = 0;
	ota_proc_step  = OTA_STEP_GET_INFO;

    osal_flag_clear(g_ota_flg_id,OTA_FLAG_PTN);
	ota_get_download_info(ota_pid,&ota_dl_info);
}

static INT32 win_otaupg_download(void)
{
	ota_proc_ret = 0;
	ota_user_stop = 0;
	ota_proc_step = OTA_STEP_DOWNLOADING;

    osal_flag_clear(g_ota_flg_id,OTA_FLAG_PTN);
    ota_start_download(ota_pid,win_ota_upgrade_process_update); 
}

#ifdef M36F_CHIP_MODE
#ifdef DUAL_ENABLE
static BOOL otaupg_fw_signed_check(void)
{
	UINT8 bl_signed[256] = {0xFF};
	struct sto_device *psto_dev = NULL;
	UINT32 offset = 0;
	UINT32 cnt = 0;
	BOOL ret = FALSE;

	psto_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
	offset = sto_fetch_long(0+CHUNK_OFFSET) - 0x100;
	sto_get_data(psto_dev, bl_signed, offset, 0x100);
	for (cnt = 0; cnt < 256; cnt ++)
	{
		if (0xFF != bl_signed[cnt] && 0x0 != bl_signed[cnt])
		{
			ret = TRUE;
			break;
		}
	}
	if (256 == cnt)
		ret = FALSE;

	return ret;
}

static BOOL otaupg_allcode_check(UINT8 *pbuff, UINT32 length)
{
	struct sto_device *flash_dev = NULL;
	UINT32 chunk_id = 0xFFFFFFFF;
	CHUNK_HEADER chunk_header;
	UINT8 *data_addr = NULL;
	UINT32 data_len = 0;
	BOOL ret = TRUE;

	if (NULL == pbuff || 0 == length)
	{
		ASSERT(0);
		return FALSE;
	}

	chunk_init((UINT32)pbuff, length);	
	// step 2: maincode check
	// get maincode raw data address & length	
	chunk_id = MAINCODE_ID;
	if(!get_chunk_header(chunk_id, &chunk_header))
	{
		ret = FALSE;
		libc_printf("get main code chunk header failed!\n");
		return ret;
	}
	data_addr = chunk_goto(&chunk_id, 0xFFFFFFFF, 1) + CHUNK_HEADER_SIZE;
	data_len = chunk_header.len - CHUNK_HEADER_SIZE + CHUNK_NAME;
	
	if (0 != Test_RSA_Ram((UINT32)data_addr, data_len)) // this function operate RAW Data and RAW length
	{
		ret = FALSE;
		return ret;
	}

	// step 3: seecode check
	// get raw data address & length from memory
	chunk_id = SEECODE_ID;
	if (!get_chunk_header(chunk_id, &chunk_header))
	{
		ret = FALSE;
		return ret;
	}
	data_addr = chunk_goto(&chunk_id, 0xFFFFFFFF, 1) + CHUNK_HEADER_SIZE;
	data_len = chunk_header.len - CHUNK_HEADER_SIZE + CHUNK_NAME;
	if (0 != Test_RSA_Ram((UINT32)data_addr, data_len))
	{
		ret = FALSE;
		return ret;
	}

	return ret;
}
#endif
#endif

#ifdef _CAS9_CA_ENABLE_

static INT32 win_otaupg_burnflash(void)
{
	BOOL fw_not_match = FALSE;
	ota_proc_ret = 0;
	ota_user_stop = 0;
	ota_proc_step = OTA_STEP_BURNFLASH;
    win_popup_choice_t choice;
    UINT8 back_saved;
	struct otaupg_ver_info ver_info;
	struct sto_device *flash_dev = NULL;
	UINT32 chunk_id, chunk_addr, chunk_size;

    osal_flag_clear(g_ota_flg_id, OTA_FLAG_PTN);

	InitStorage();
#if defined(_M3383_SABBAT_) || defined(_ENABLE_4M_FLASH_) 	
	SetupOtaParameters();
#endif
	MEMSET(&ver_info, 0, sizeof(struct otaupg_ver_info));
	otaupg_check(&ver_info);

	#ifdef OTA_NO_VERION_CHK //just for no version verify 
	ver_info.m_f_ver = 1;
	ver_info.m_m_ver = 2;
	ver_info.o_b_ver = 1;
	ver_info.o_f_ver = 1;
	ver_info.o_m_ver = 2;
	ver_info.s_f_ver = 1;
	ver_info.s_m_ver = 2;
	#endif
	if (
		(ver_info.o_m_ver == 0) ||
		(ver_info.m_m_ver == 0) ||
		(ver_info.s_m_ver == 0) || 
		(ver_info.m_m_ver != ver_info.s_m_ver))
	{
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg("Invalid OTA data, cannot burn it!", NULL, 0);
		win_compopup_set_default_choice(WIN_POP_CHOICE_YES);
		win_compopup_open_ext(&back_saved);
		osal_flag_set(g_ota_flg_id, PROC_FAILURE);
		return -1;
	}

	UINT32 upgrade_size = 0;

#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
	if (ver_info.o_m_ver > ver_info.o_f_ver)
		upgrade_size += m_ota_info.ota_loader_size;
#endif

	if (ver_info.m_m_ver > ver_info.m_f_ver)
		upgrade_size += m_ota_info.main_code_size;
	
	if (ver_info.s_m_ver > ver_info.s_f_ver)
		upgrade_size += m_ota_info.see_code_size;

	// Oncer Yu 20110725:
	// As M3603 Mode, need to check OTALoader/MainCode/SeeCode
	// but M3383 mode, neet to check MainCode/SeeCode firstly
	// if need to do upgrade, then do OTALoader check
	if (upgrade_size == 0)
	{
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg("Nothing need to be upgrade!", NULL, 0);
		win_compopup_set_default_choice(WIN_POP_CHOICE_YES);
		win_compopup_open_ext(&back_saved);
		osal_flag_set(g_ota_flg_id, PROC_FAILURE);
		return -1;
	}
#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
	else if (ver_info.o_f_ver > ver_info.o_b_ver)
	{
		upgrade_size += OTA_LOADER_BACKUP_LEN + DECRYPT_KEY_BACKUP_LEN;
	}
#else
	else if(ver_info.o_m_ver > ver_info.o_f_ver)
	{		
	#ifndef _BUILD_OTA_E_
		upgrade_size += m_ota_info.ota_loader_size;
		upgrade_size += m_ota_info.user_db_len;
	#endif
	}
	else
	{
		// if enter here, that means OTA Loader Invalid!!!
		win_compopup_init(WIN_POPUP_TYPE_OK);
		win_compopup_set_msg("OTA Invalid!", NULL, 0);
		win_compopup_set_default_choice(WIN_POP_CHOICE_YES);
		win_compopup_open_ext(&back_saved);
		osal_flag_set(g_ota_flg_id, PROC_FAILURE);
		return -1;
	}
#endif	
	
	m_ota_info.update_total_sectors = upgrade_size / C_SECTOR_SIZE;
	m_ota_info.update_secotrs_index = 0;

	INT32 ret = 0;
	UINT32 flash_pos;
	do {
	#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)
		if (ver_info.o_f_ver > ver_info.o_b_ver)
		{
			// backup ota loader and universal key
			OTA_PRINTF("backup ota loader and universal key\n");
			flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
			chunk_id = OTA_LOADER_CHUNK_ID;
			chunk_size = OTA_LOADER_BACKUP_LEN;
			chunk_addr = (UINT32)sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
			if (chunk_addr == (UINT32)ERR_FAILUE)
			{
				ret = ERR_FAILED;
				break;
			}
			if (sto_get_data(flash_dev, (UINT8 *)m_ota_info.cipher_buf_addr, chunk_addr, chunk_size) == chunk_size)
			{
				flash_pos = OTA_LOADER_BACKUP_ADDR / C_SECTOR_SIZE;
				ret = BurnBlock((UINT8 *)m_ota_info.cipher_buf_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
				if (SUCCESS != ret)
					break;
			}

			chunk_id = DECRPT_KEY_ID;
			chunk_size = DECRYPT_KEY_BACKUP_LEN;
			chunk_addr = (UINT32)sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
			if (chunk_addr == (UINT32)ERR_FAILUE)
			{
				ret = ERR_FAILED;
				break;
			}
			if (sto_get_data(flash_dev, (UINT8 *)m_ota_info.cipher_buf_addr, chunk_addr, chunk_size) == chunk_size)
			{
				flash_pos = DECRYPT_KEY_BACKUP_ADDR / C_SECTOR_SIZE;
				ret = BurnBlock((UINT8 *)m_ota_info.cipher_buf_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
				if (SUCCESS != ret)
					break;
			}
		}
	#endif	

#if !defined (_M3383_SABBAT_) &&  !defined (_ENABLE_4M_FLASH_)	
		// ota loader chunk addr and size
		chunk_id = OTA_LOADER_CHUNK_ID;
		chunk_addr = (UINT32)sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
		if (chunk_addr == (UINT32)ERR_FAILUE)
		{
			OTA_PRINTF("Cannot find ota loader's chunk!\n");
			ret = ERR_FAILED;
			break;
		}
		
		chunk_size = m_ota_info.ota_loader_size;
		if (ver_info.o_m_ver > ver_info.o_f_ver)
		{
			OTA_PRINTF("upgrade ota loader\n");
			flash_pos = chunk_addr / C_SECTOR_SIZE;
			ret = BurnBlock((UINT8 *)m_ota_info.ota_loader_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
			if (SUCCESS != ret)
				break;
		}
#else

#ifndef _BUILD_OTA_E_
		// TODO: step 1: backup UserDB
		OTA_PRINTF("BackupDataBase!\n");
		ret = BackupDatabase();
		if (SUCCESS != ret)
			break;
		
		// TODO: step 2: burn OTA to UserDB
		OTA_PRINTF("Burn OTALOADER!\n");
		ret = BurnBlock((UINT8*)m_ota_info.ota_bin_addr, m_ota_info.user_db_start_sector , m_ota_info.ota_bin_sectors);
        if(SUCCESS != ret)
            break;
#endif		

		// TODO: step 3: calculate maincode chunk_addr
		chunk_id = MAINCODE_ID;
		chunk_addr = (UINT32)sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
		if ((UINT32)ERR_FAILUE == chunk_addr)
		{
			OTA_PRINTF("Cannot find maincode's chunk!\n");
#ifdef _BUILD_OTA_E_
            //when cannot find maincode chunk,we use maincode chunk addr in mem.
            if(0 != m_ota_info.main_code_addr && 0 != m_ota_info.ota_fw_addr)
                chunk_addr = m_ota_info.main_code_addr - m_ota_info.ota_fw_addr;
            if(chunk_addr <= 0)
            {
                ret = ERR_FAILED;
			    break;                
            }
#else
			ret = ERR_FAILED;
			break;
#endif
		}
		chunk_size = 0;
#endif

		// burn new maincode.bin
		// main code chunk addr and size
		chunk_addr += chunk_size;
		chunk_size = m_ota_info.main_code_size;
		if (ver_info.m_m_ver > ver_info.m_f_ver)
		{
			OTA_PRINTF("upgrade main code\n");
			flash_pos = chunk_addr / C_SECTOR_SIZE;
			ret = BurnBlock((UINT8 *)m_ota_info.main_code_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
			if (SUCCESS != ret)
				break;
		}

		// see code chunk addr and size
		chunk_addr += chunk_size;
		chunk_size = m_ota_info.see_code_size;
		if (ver_info.s_m_ver > ver_info.s_f_ver)
		{
			OTA_PRINTF("upgrade see code\n");
			flash_pos = chunk_addr / C_SECTOR_SIZE;
			ret = BurnBlock((UINT8 *)m_ota_info.see_code_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
			if (SUCCESS != ret)
				break;
		}
#if (defined _S3281_ && defined _VERSION_CONTROL_)
		if(!version_update(ver_info.m_m_ver,SW_VER))
		{
			OTA_PRINTF("update code version fail\n");
			win_compopup_init(WIN_POPUP_TYPE_SMSG);
			win_compopup_set_msg("Update version fail!", NULL, 0);
			win_compopup_open_ext(&back_saved);
			while(1);
		}
#endif

#if defined( _M3383_SABBAT_ ) ||defined(_ENABLE_4M_FLASH_)
	#ifndef _BUILD_OTA_E_
		// TODO: burn back UserDB
		OTA_PRINTF("BurnBack UserDB!\n");
		ret = BurnBlock((UINT8*)m_ota_info.backup_db_addr, m_ota_info.user_db_start_sector, m_ota_info.user_db_sectors);
        if(SUCCESS != ret)
            break;
	#endif	
#endif
	} while(0);
	
	osal_flag_set(g_ota_flg_id,(ret == SUCCESS) ? PROC_SUCCESS : PROC_FAILURE);
    return ret;
}

#else /* _CAS9_CA_ENABLE_ */
#ifdef _VMX_CA_ENABLE_
struct otaupg_ver_info
{
	UINT32 o_f_ver;	// ota loader in flash version
	UINT32 o_m_ver;	// ota loader in memory version
	UINT32 m_f_ver;	// main code in flash version
	UINT32 m_m_ver;	// main code in memory version
	UINT32 s_f_ver;	// see code in flash version
	UINT32 s_m_ver;	// see code in memory version
};


#ifdef FAKE_VERITY_SIGNATURE
	#define BC_VerifySignature  FakeBC_VerifySignature
/****************************************************************************
 *  ViewRight Functions
 ****************************************************************************/
// typedef unsigned long long uint64_t;

static uint8_t magic[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };

uint32_t crc32(uint8_t *data, uint32_t len)
{
	return MG_Table_Driven_CRC(0xFFFFFFFF, data, len);
}

uint64_t getNumber( uint8_t* ptr ) 
{
	uint64_t tmpVal = 0;
	int i;
	// data in the signature is big-endian
	for( i = 0; i < 8; i++ ) 
	{
		tmpVal = (tmpVal<<8) | ptr[i];
	}
	return tmpVal;
}

uint8_t checkTheDataAndHash(uint8_t *data, uint32_t len, uint8_t* signature)
{

	// this function verifies the hash values and determines whether a
	// re-encryption is needed
	uint32_t tmpCrc = crc32( data, len );

	/* we only have put 32-bits into the signature therefore we type-cast and correct the offset by 4 */
	if( ( (uint32_t)getNumber( signature + 48 - 4 ) ) == tmpCrc )
	{
	#if 1	// here we "decrypt" by using xor
		int j;
		OTA_PRINTF("checkTheDataAndHash: tmpCrc=0x%x match, decrypt the source\n",tmpCrc);
		for( j = 0; j < len; j++ )
			data[j] ^= 0xff;
	#endif
		return 0;
	}
	else 
	{
		// here we can already "re-encrypt" by using xor
		int i;
		for( i = 0; i < len; i++ )
			data[i] ^= 0xff;
		tmpCrc = crc32( data, len );
		/* we only have put 32-bits into the signature therefore we type-cast and
		correct the offset by 4 */
		if( ( (uint32_t)getNumber( signature + 48 - 4 ) ) != tmpCrc )
		{
			// the crc does not match therefore there it is an error
			OTA_PRINTF("checkTheDataAndHash: crc error tmpCrc=0x%x\n",tmpCrc);
			return 2;
		}
		return 1;
	}

}

uint8_t decryptSignature( uint8_t* decSignature, uint8_t* signature ) 
{
	// here we do signature decryption
	// we only copy here as the signature is not encrypted at all
	memcpy( decSignature, signature, 256 );
	return 1;
}

int BC_VerifySignature( uint8_t* signature, uint8_t* src, uint8_t* tmp,uint32_t len, uint32_t maxLen, uint8_t mode,uint8_t *errorCode ) 
{
	uint8_t decSignature[256];

	OTA_PRINTF("verifySignature: len=0x%x, maxLen=0x%x, mode=%d\n",len, maxLen, mode);
	OTA_PRINTF("verifySignature: signature crc=0x%x 0x%x 0x%x 0x%x\n",signature[48],signature[49],signature[50],signature[51]);
	OTA_PRINTF("verifySignature: signature len=0x%x 0x%x 0x%x 0x%x\n",signature[36],signature[37],signature[38],signature[39]);
	OTA_PRINTF("verifySignature: signature maxlen=0x%x 0x%x 0x%x 0x%x\n",signature[44],signature[45],signature[46],signature[47]);
#ifdef DEBUG_MODE_VERITY_SIGNATURE
	// for loading real CT application to flash
	*errorCode = 2;
	return 0;
#endif
	// we decrypt the signature, which you do not have to do here
	if( decryptSignature( decSignature, signature ) ) 
	{
		if( memcmp( decSignature, magic, 8 ) ) 
		{
			// error magic value is wrong, therefore signature is bad
			OTA_PRINTF("verifySignature: magic value wrong:0x%x 0x%x\n",decSignature[0], decSignature[1]);
			*errorCode = 1;
			return 0;
		}
		else 
		{
			int i;
			for( i = 9; i < 24; i++ ) 
			{
				if( decSignature[i] ) 
				{
					// error verifier is not 0, therefore signature is bad
					OTA_PRINTF("verifySignature: zero value wrong:decSignature[%d]= 0x%x\n",i,decSignature[i]);
					*errorCode = 1;
					return 0;
				}
			}
			// the signature has been decrypted correctly, now we check the
			// length values
			if( ( getNumber( decSignature+32 ) == len ) &&( getNumber( decSignature+40 ) == maxLen ) ) 
			{
				// now we do some additional checks for hash-value
				// and from this check we determine whether a
				// re-encryption is needed
				uint8_t re_encryption_needed = checkTheDataAndHash( src, len, decSignature );
				OTA_PRINTF("verifySignature: re_encryption_needed=%d\n",re_encryption_needed);
				if( re_encryption_needed == 2 ) 
				{
					// error the hash value is not correct,
					// therefore signature is bad
					*errorCode = 1;
					return 0;
				}
				// if re-encryption is needed we check, for the mode value.
				if( re_encryption_needed && ( decSignature[8] == 1 ) &&( mode == 0 ) ) 
				{
					// error re-encryption when starting from flash must not occur
					// for loaded image, therefore signature is bad
					OTA_PRINTF("verifySignature: mode not match error\n");
					*errorCode = 1;
					return 0;
				}
				
				if( re_encryption_needed ) 
				{
					// do the re-encryption
					// we have already done it
					*errorCode = 2;
					return 0;
				}
				else 
				{
					if( mode == 1 ) 
					{
						// error there should be no re-encrypted image directly loaded
						OTA_PRINTF("verifySignature: error mode should be 0\n");
						* errorCode = 1;
						return 0;
					}
					else 
					{
						// everything is fine
						*errorCode = 0;
						return 1;
					}
				}
			}
			else 
			{
				// error one of the length values does not match,
				// therefore signature is bad
				OTA_PRINTF("verifySignature: len wrong: len=0x%x 0x%x 0x%x 0x%x\n",decSignature[32+4], decSignature[32+5],decSignature[32+6], decSignature[32+7]);
				OTA_PRINTF("verifySignature: maxlen wrong: maxlen=0x%x 0x%x 0x%x 0x%x\n",decSignature[40+4], decSignature[40+5],decSignature[40+6], decSignature[40+7]);
				*errorCode = 1;
				return 0;
			}
		}
	}
	else 
	{
		// error decryption failed, therefore signature is bad
		OTA_PRINTF("verifySignature: decryption failed\n");
		*errorCode = 1;
		return 0;
	}
}
#endif

static INT8 Char2Hex(UINT8 ch)
{
	INT8 ret =  - 1;
	if ((ch <= 0x39) && (ch >= 0x30))
	// '0'~'9'
		ret = ch &0xf;
	else if ((ch <= 102) && (ch >= 97))
	//'a'~'f'
		ret = ch - 97+10;
	else if ((ch <= 70) && (ch >= 65))
	//'A'~'F'
		ret = ch - 65+10;

	return ret;
}

static UINT32 Str2UINT32(UINT8 *str, UINT8 len)
{
	UINT32 ret = 0;
	UINT8 i;
	INT temp;

	if (str == NULL)
		return 0;

	for (i = 0; i < len; i++)
	{
		temp = Char2Hex(*str++);
		if (temp ==  - 1)
			return 0;

		ret = (ret << 4) | temp;
	}

	return ret;
}


static BOOL otaupg_check(struct otaupg_ver_info *ver_info)
{
	struct sto_device *flash_dev = NULL;
	UINT32 chunk_id = 0;
	UINT8 *data;
	UINT32 data_len;
	UINT8 *block_addr;
	int ret;	
	uint8_t* signature;
	uint8_t* tmp_buffer;
	uint32_t len, maxLen;
	uint8_t mode, errorCode;
	unsigned int header_crc=0;
	//UINT32 block_header, version;
	CHUNK_HEADER blk_header;
	UINT8 verify_result=0;

	#define MAIN_CODE_CHUNK_ID		0x01FE0101
	#define SEE_CODE_CHUNK_ID		0x06F90101
	#define SIGNATURE_SIZE 		256
	#define SAVE_MAIN			0x1
	#define SAVE_SEE			0x2
	#define SAVE_OTA_LOADER		0x4

	// get unzip size
	m_ota_info.uncompressed_len = (UINT32)get_unzip_size((UINT8 *)m_ota_info.compressed_addr);
	chunk_init(m_ota_info.uncompressed_addr, m_ota_info.uncompressed_len);

	tmp_buffer = (UINT8 *)m_ota_info.tmp_buf_addr;
	MG_Setup_CRC_Table();
	OTA_PRINTF("check ota loader in memory\n");

	block_addr = (UINT8 *)m_ota_info.ota_bin_addr;
	m_ota_info.ota_bin_size = fetch_long(block_addr + CHUNK_OFFSET);
	data_len = fetch_long(block_addr + CHUNK_LENGTH);
	data = block_addr+CHUNK_HEADER_SIZE;

	len=data_len-(CHUNK_HEADER_SIZE-CHUNK_NAME)-SIGNATURE_SIZE;
	signature=data+len;
	//maxLen=m_ota_info.ota_bin_size;  //Clarify 20120806
	maxLen=len;
	mode=1;		//from loader
	ret=BC_VerifySignature(signature, data, tmp_buffer, len, maxLen, mode,&errorCode);
	if(ret==1)	//app can be started
	{
		OTA_PRINTF("ota loader cannot be started in loader mode\n");
	}
	else	// don't start app
	{
		if(errorCode==2)	//store app to flash and reboot later
		{
			ver_info->o_m_ver = Str2UINT32(block_addr+CHUNK_VERSION, 8);
			//calculate crc value for chunk header
			header_crc=MG_Table_Driven_CRC(0xFFFFFFFF, block_addr+CHUNK_NAME, data_len);
			*(block_addr+CHUNK_CRC)=(UINT8)(header_crc>>24);
			*(block_addr+CHUNK_CRC+1)=(UINT8)(header_crc>>16);
			*(block_addr+CHUNK_CRC+2)=(UINT8)(header_crc>>8);
			*(block_addr+CHUNK_CRC+3)=(UINT8)(header_crc);
			OTA_PRINTF("ota block header_crc=0x%x first byte=0x%x\n",header_crc,*(block_addr+CHUNK_CRC));
			OTA_PRINTF("ota loader verify ok and re-encrypt\n");
			verify_result|=SAVE_OTA_LOADER;
		}
		else if(errorCode==1)
		{
			OTA_PRINTF("ota code verify failed\n");
		}
	}

	OTA_PRINTF("ota loader: 0x%X, 0x%X\n", m_ota_info.ota_bin_addr, m_ota_info.ota_bin_size);

	OTA_PRINTF("check main code in memory\n");
	chunk_id = MAIN_CODE_CHUNK_ID;
	m_ota_info.main_code_addr = (UINT32)chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
	if (m_ota_info.main_code_addr)
	{
		block_addr = (UINT8 *)m_ota_info.main_code_addr;
		m_ota_info.main_code_size = fetch_long(block_addr + CHUNK_OFFSET);
		data_len = fetch_long(block_addr + CHUNK_LENGTH);
		data = block_addr+CHUNK_HEADER_SIZE;

		len=data_len-(CHUNK_HEADER_SIZE-CHUNK_NAME)-SIGNATURE_SIZE;
		signature=data+len;
		//maxLen=m_ota_info.main_code_size; //Clarify 20120806
		maxLen=len;
		mode=1;		//from loader
		ret=BC_VerifySignature(signature, data, tmp_buffer, len, maxLen, mode,&errorCode);
		if(ret==1)	//app can be started
		{
			OTA_PRINTF("main code cannot be started in loader mode\n");
		}
		else	// don't start app
		{
			if(errorCode==2)	//store app to flash and reboot later
			{
				ver_info->m_m_ver = Str2UINT32(block_addr+CHUNK_VERSION, 8);
				//calculate crc value for chunk header
				header_crc=MG_Table_Driven_CRC(0xFFFFFFFF, block_addr+CHUNK_NAME, data_len);
				*(block_addr+CHUNK_CRC)=(UINT8)(header_crc>>24);
				*(block_addr+CHUNK_CRC+1)=(UINT8)(header_crc>>16);
				*(block_addr+CHUNK_CRC+2)=(UINT8)(header_crc>>8);
				*(block_addr+CHUNK_CRC+3)=(UINT8)(header_crc);
				OTA_PRINTF("main block header_crc=0x%x first byte=0x%x\n",header_crc,*(block_addr+CHUNK_CRC));
				OTA_PRINTF("main code verify ok and re-encrypt\n");
				verify_result|=SAVE_MAIN;
			}
			else if(errorCode==1)
			{
				OTA_PRINTF("main code verify failed\n");
			}
		}
	}
	OTA_PRINTF("main code: 0x%X, 0x%X\n", m_ota_info.main_code_addr, m_ota_info.main_code_size);

	OTA_PRINTF("check see code in memory\n");
	chunk_id = SEE_CODE_CHUNK_ID;
	m_ota_info.see_code_addr = (UINT32)chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
	if (m_ota_info.see_code_addr)
	{
		block_addr = (UINT8 *)m_ota_info.see_code_addr;
		m_ota_info.see_code_size = fetch_long(block_addr + CHUNK_OFFSET);
		data_len = fetch_long(block_addr + CHUNK_LENGTH);
		data = block_addr+CHUNK_HEADER_SIZE;

		len=data_len-(CHUNK_HEADER_SIZE-CHUNK_NAME)-SIGNATURE_SIZE;
		signature=data+len;
		//maxLen=m_ota_info.see_code_size;  //Clarify 20120806
		maxLen=len;
		mode=1;		//from loader
		ret=BC_VerifySignature(signature, data, tmp_buffer, len, maxLen, mode,&errorCode);
		if(ret==1)	//app can be started
		{
			OTA_PRINTF("see code cannot be started in loader mode\n");
		}
		else	// don't start app
		{
			if(errorCode==2)	//store app to flash and reboot later
			{
				ver_info->s_m_ver = Str2UINT32(block_addr+CHUNK_VERSION, 8);
				//calculate crc value for chunk header
				header_crc=MG_Table_Driven_CRC(0xFFFFFFFF, block_addr+CHUNK_NAME, data_len);
				*(block_addr+CHUNK_CRC)=(UINT8)(header_crc>>24);
				*(block_addr+CHUNK_CRC+1)=(UINT8)(header_crc>>16);
				*(block_addr+CHUNK_CRC+2)=(UINT8)(header_crc>>8);
				*(block_addr+CHUNK_CRC+3)=(UINT8)(header_crc);
				OTA_PRINTF("see block header_crc=0x%x first byte=0x%x\n",header_crc,*(block_addr+CHUNK_CRC));
				OTA_PRINTF("see code verify ok and re-encrypt\n");
				verify_result|=SAVE_SEE;
			}
			else if(errorCode==1)
			{
				OTA_PRINTF("see code verify failed\n");
			}
		}
		
	}
	OTA_PRINTF("see code: 0x%X, 0x%X\n", m_ota_info.see_code_addr, m_ota_info.see_code_size);

#ifdef	_BUILD_OTA_E_
	//because the function of ota_load_parameter will call sto_chunk_init to find ota parameter.
	//sto_chunk_init again
	flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
	if (flash_dev == NULL)
	{
		OTA_PRINTF("Can't find FLASH device!\n");
	}
	sto_open(flash_dev);
	sto_chunk_init(0, flash_dev->totol_size);
#endif

	chunk_id=MAIN_CODE_CHUNK_ID;
	if(sto_get_chunk_header(chunk_id, &blk_header))
	{
		ver_info->m_f_ver = Str2UINT32(blk_header.version, 8);
	}

	chunk_id=SEE_CODE_CHUNK_ID;
	if(sto_get_chunk_header(chunk_id, &blk_header))
	{
		ver_info->s_f_ver = Str2UINT32(blk_header.version, 8);
	}
	
	OTA_PRINTF("version info: (0x%X, 0x%X), (0x%X, 0x%X), (0x%X, 0x%X)\n",
		ver_info->o_f_ver, ver_info->o_m_ver, ver_info->m_f_ver,
		ver_info->m_m_ver, ver_info->s_f_ver, ver_info->s_m_ver);

	OTA_PRINTF("verify result=0x%x\n",verify_result);
	if(verify_result==(SAVE_MAIN|SAVE_SEE|SAVE_OTA_LOADER))
	{
		return TRUE;	//save apps to flash
	}
	else
	{
		return FALSE;
	}
}

static INT32 win_otaupg_burnflash(void)
{
	BOOL fw_not_match = FALSE;
	ota_proc_ret = 0;
	ota_user_stop = 0;
	ota_proc_step = OTA_STEP_BURNFLASH;
    win_popup_choice_t choice;
    UINT8 back_saved;
	struct otaupg_ver_info ver_info;
	struct sto_device *flash_dev = NULL;
	UINT32 chunk_id, chunk_addr, chunk_size;
	BOOL check_ret;

    osal_flag_clear(g_ota_flg_id, OTA_FLAG_PTN);

	InitStorage();
	
	SetupOtaParameters();

	MEMSET(&ver_info, 0, sizeof(struct otaupg_ver_info));
	check_ret=otaupg_check(&ver_info);
	if((check_ret!=TRUE)||(ver_info.m_m_ver != ver_info.s_m_ver))
	{
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg("Invalid OTA data, cannot burn it!", NULL, 0);
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(3000);
		win_compopup_smsg_restoreback();		
		osal_flag_set(g_ota_flg_id, PROC_FAILURE);
		return -1;
	}

	UINT32 upgrade_size = 0;

	if((ver_info.m_m_ver >= ver_info.m_f_ver)&&(ver_info.s_m_ver >= ver_info.s_f_ver))
	{
		upgrade_size += m_ota_info.main_code_size;
		upgrade_size += m_ota_info.see_code_size;
	}
#ifndef _BUILD_OTA_E_
	else
	{
		//OSM_TRIGGERS* pOSM_Triggers=GetOsmTriggers();
		//if(pOSM_Triggers->OTA_Type==OSM_FORCED)
		extern OSM_ACTION_TYPE backup_ota_type;
		if(backup_ota_type==OSM_FORCED)
		{
			upgrade_size += m_ota_info.main_code_size;
			upgrade_size += m_ota_info.see_code_size;
		}
	}
#endif

	if (upgrade_size == 0)
	{
		win_compopup_init(WIN_POPUP_TYPE_SMSG);
		win_compopup_set_msg("Nothing need to be upgrade!", NULL, 0);
		win_compopup_open_ext(&back_saved);
		osal_task_sleep(3000);
		win_compopup_smsg_restoreback();
		osal_flag_set(g_ota_flg_id, PROC_FAILURE);
		return -1;
	}
		
#ifndef _BUILD_OTA_E_
	upgrade_size += m_ota_info.ota_bin_size;
	upgrade_size += m_ota_info.user_db_len;
#else
	upgrade_size += m_ota_info.user_db_len;
#endif
	
	m_ota_info.update_total_sectors = upgrade_size / C_SECTOR_SIZE;
	m_ota_info.update_secotrs_index = 0;

	INT32 ret = 0;
	UINT32 flash_pos;
	do {
	#ifndef _BUILD_OTA_E_
		// TODO: step 1: backup UserDB
		OTA_PRINTF("BackupDataBase!\n");
		ret = BackupDatabase();
		if (SUCCESS != ret)
			break;
		
		// TODO: step 2: burn OTA to UserDB
		OTA_PRINTF("Burn OTALOADER!\n");
		ret = BurnBlock((UINT8*)m_ota_info.ota_bin_addr, m_ota_info.user_db_start_sector , m_ota_info.ota_bin_sectors);
        if(SUCCESS != ret)
            break;
	#endif		

		// TODO: step 3: calculate maincode chunk_addr
		chunk_id = MAINCODE_ID;
		chunk_addr = (UINT32)sto_chunk_goto(&chunk_id, 0xFFFFFFFF, 1);
		if ((UINT32)ERR_FAILUE == chunk_addr)
		{
			OTA_PRINTF("Cannot find maincode's chunk!\n");
			ret = ERR_FAILED;
			break;
		}
		chunk_size = 0;

		// burn new maincode.bin
		// main code chunk addr and size
		chunk_addr += chunk_size;
		chunk_size = m_ota_info.main_code_size;
		OTA_PRINTF("upgrade main code\n");
		flash_pos = chunk_addr / C_SECTOR_SIZE;
		ret = BurnBlock((UINT8 *)m_ota_info.main_code_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
		if (SUCCESS != ret)
			break;

		// see code chunk addr and size
		chunk_addr += chunk_size;
		chunk_size = m_ota_info.see_code_size;
		OTA_PRINTF("upgrade see code\n");
		flash_pos = chunk_addr / C_SECTOR_SIZE;
		ret = BurnBlock((UINT8 *)m_ota_info.see_code_addr, flash_pos, chunk_size/C_SECTOR_SIZE);
		if (SUCCESS != ret)
			break;
		
	#ifndef _BUILD_OTA_E_
		// TODO: burn back UserDB
		OTA_PRINTF("BurnBack UserDB!\n");
		ret = BurnBlock((UINT8*)m_ota_info.backup_db_addr, m_ota_info.user_db_start_sector, m_ota_info.user_db_sectors);
        if(SUCCESS != ret)
            break;
	#else
		OTA_PRINTF("reset UserDB!\n");
		ret = BurnBlock((UINT8*)NULL, m_ota_info.user_db_start_sector, m_ota_info.user_db_sectors);
        if(SUCCESS != ret)
            break;
	#endif	
	} while(0);

	osal_flag_set(g_ota_flg_id,(ret == SUCCESS) ? PROC_SUCCESS : PROC_FAILURE);
    return ret;
}

#else
static INT32 win_otaupg_burnflash(void)
{
	BOOL fw_not_match = FALSE;
	ota_proc_ret = 0;
	ota_user_stop = 0;
	ota_proc_step = OTA_STEP_BURNFLASH;
    win_popup_choice_t choice;
    UINT8 back_saved;

    osal_flag_clear(g_ota_flg_id,OTA_FLAG_PTN);

#if 1	
	InitStorage();
       ciFlag=Bool_flash_mem();   //add by colin
	SetupOtaParameters();

	UINT32 ota_fw_chip_id = (*(UINT32 *)(m_ota_info.ota_fw_addr + CHUNK_HEADER_SIZE + 0x80)) & 0xFFFF0000;

	if(sys_ic_get_chip_id() >= ALI_S3602F)
	{
		if(ota_fw_chip_id != (*(UINT32 *)(0xb8000000))&0xffff0000)
			fw_not_match = TRUE;
	}
	else
	{
		if(ota_fw_chip_id == 0x36060000)
			fw_not_match = TRUE;
	}

    if (fw_not_match)
    {
        win_compopup_init(WIN_POPUP_TYPE_OKNO);
        win_compopup_set_msg("FW/IC Version not match!", NULL, 0);
        win_compopup_set_default_choice(WIN_POP_CHOICE_NO);
        choice = win_compopup_open_ext(&back_saved);
        if (WIN_POP_CHOICE_NO == choice)
        {
			osal_flag_set(g_ota_flg_id, PROC_FAILURE);
            return -1;
        }
    }

#ifdef CI_PLUS_SUPPORT
    UINT8   *ci_plus_internal_keys;
    CHUNK_HEADER ci_plus_chuck_hdr;
    UINT32 ci_plus_chuck_id = 0x09F60101;           

    if(!backup_chunk_data(m_ota_info.ota_fw_addr, m_ota_info.ota_fw_size, ci_plus_chuck_id))
		return -1;

#endif

#ifdef M36F_CHIP_MODE	
#ifdef DUAL_ENABLE
	if (TRUE == otaupg_fw_signed_check())
	{
		if (FALSE == otaupg_allcode_check((UINT8 *)m_ota_info.ota_fw_addr, m_ota_info.ota_fw_size))
			return -1;
	}
#endif
#endif

	INT32 ret = BurnFlash();
	osal_flag_set(g_ota_flg_id,(ret == SUCCESS)?PROC_SUCCESS:PROC_FAILURE);
#else

    ota_start_burnflash(win_ota_upgrade_process_update);
#endif	
    return 0;
}
#endif
#endif /* _CAS9_CA_ENABLE_ */

static INT32 win_otaupg_reboot(void)
{
	ota_proc_ret = 0;
	ota_user_stop = 0;
	//ota_proc_step = OTA_STEP_BURNFLASH;
	#ifdef AUTO_OTA
	set_ota_upgrade_found(FALSE);
	#endif
	osal_flag_clear(g_ota_flg_id,OTA_FLAG_PTN);

	key_pan_display("OFF ",4);
	osal_task_sleep(500);
	power_off_process(0);

	// Oncer 2011/03/0915:43
	// for OTA upgrade, we need to save UserDB, so don't need to do factory init!!!
//    sys_data_factroy_init();
//    sys_data_set_factory_reset(TRUE);
    sys_data_set_cur_chan_mode(TV_CHAN);

	power_on_process();

	while(1) ;
}


static void win_otaup_set_btn_msg_display(BOOL update)
{
	MULTI_TEXT* mtxt_msg;
	TEXT_FIELD* txt_btn;
	UINT16 btn_strid;
	TEXT_CONTENT* tcont;
	UINT16 cur_sw_ver = SYS_SW_VERSION&0xffff;
	UINT8 * src;
	UINT8 str_len;
	INT32 btn_state;
    lpVSCR apvscr;
	tcont = otamsg_mtxt_content;
	tcont->bTextType = STRING_ID;

	mtxt_msg = &otaupg_mtxt_msg;
	txt_btn = &otaupg_txt_btn;	

/* 0 - stop , 1 - exit , 2 - download 3 - burnflash 4 - reboot*/
	btn_state = win_otaup_get_btn_state();
	#ifdef NEW_MANUAL_OTA
	if(btn_state == 0)
		btn_strid = RS_OTA_DOWNLOAD;
	else if(btn_state == 1)
		btn_strid = RS_OTA_DOWNLOAD;
	else if(btn_state == 2)
		btn_strid = RS_OTA_DOWNLOAD;
	else if(btn_state == 3)
		btn_strid = RS_OTA_BURNFLASH;
	else if(btn_state == 4)
		btn_strid = RS_OTA_UPGRADE_SUCCESSFUL;
	else
		btn_strid = 0;
	#else
	if(btn_state == 0)
		btn_strid = RS_DISEQC12_MOVEMENT_STOP;
	else if(btn_state == 1)
		btn_strid = RS_HELP_EXIT;
	else if(btn_state == 2)
		#ifdef _VMX_CA_ENABLE_
			btn_strid = RS_VMX_OTA_PRESS_OK_TO_DOWNLOAD;
		#else
		btn_strid = RS_DISPLAY_DOWNLOADING;
		#endif
	else if(btn_state == 3)
		#ifdef _VMX_CA_ENABLE_
			btn_strid = RS_VMX_OTA_PRESS_OK_TO_BURNFLASH;
		#else
		btn_strid = RS_OTA_BURNFLASH;
		#endif		
	else if(btn_state == 4)
		#ifdef _VMX_CA_ENABLE_
			btn_strid = RS_VMX_OTA_PRESS_OK_TO_REBOOT;
		#else
		btn_strid = RS_MSG_UPGRADE_REBOOT;
		#endif
	else
		btn_strid = 0;
	#endif

	switch(ota_proc_step)
	{
	case OTA_STEP_GET_INFO:
		
		switch(ota_proc_ret)
		{
		case 0:
			tcont->text.wStringID = RS_OTA_COLLECT_INFORMATION;
			break;
		case PROC_SUCCESS:

			if(ota_dl_info.sw_version <= cur_sw_ver)
			{
				if(ota_dl_info.sw_version < cur_sw_ver)
			 		ComAscStr2Uni("SW is older than your STB's SW! Do you want to continue?",len_display_str);
				else
					ComAscStr2Uni("SW is same to your STB's SW! Do you want to continue?",len_display_str);
			}
			else
			{
				src = OSD_GetUnicodeString(RS_DISPLAY_NEXT);
				ComUniStrCopyChar((UINT8*)len_display_str, src);
				str_len = ComUniStrLen(len_display_str);
				ComAscStr2Uni(" : ",&len_display_str[str_len]);
				str_len = ComUniStrLen(len_display_str);
				src = OSD_GetUnicodeString(RS_DISPLAY_DOWNLOADING);
				ComUniStrCopyChar((UINT8*)&len_display_str[str_len], src);
			}
			
			tcont->bTextType = STRING_UNICODE;
			tcont->text.pString = len_display_str;
			
			break;
		case PROC_STOPPED:
			ComAscStr2Uni("User canceled",len_display_str);
			
			tcont->bTextType = STRING_UNICODE;
			tcont->text.pString = len_display_str;			
			break;
		case PROC_FAILURE:
			tcont->text.wStringID = RS_OTA_COLLECT_INFORMATION_FAIL;						
			break;			
		}

		break;
	case OTA_STEP_DOWNLOADING:	
		
		switch(ota_proc_ret)
		{
		case 0:
			tcont->text.wStringID = RS_DISPLAY_DOWNLOADING;
			break;
		case PROC_SUCCESS:		
			src = OSD_GetUnicodeString(RS_DISPLAY_NEXT);
			ComUniStrCopyChar((UINT8*)len_display_str, src);
			str_len = ComUniStrLen(len_display_str);
			ComAscStr2Uni(" : ",&len_display_str[str_len]);
			str_len = ComUniStrLen(len_display_str);
			src = OSD_GetUnicodeString(RS_OTA_BURNFLASH);
			ComUniStrCopyChar((UINT8*)&len_display_str[str_len], src);

			tcont->bTextType = STRING_UNICODE;
			tcont->text.pString = len_display_str;
			
			break;
		case PROC_STOPPED:
			ComAscStr2Uni("User canceled",len_display_str);
			
			tcont->bTextType = STRING_UNICODE;
			tcont->text.pString = len_display_str;			
			break;
		case PROC_FAILURE:
			tcont->text.wStringID = RS_DISPLAY_DOWNLOAD_NOT_FINISH;
			break;
		}
		break;
		
	case OTA_STEP_BURNFLASH:

		switch(ota_proc_ret)
		{
		case 0:
			tcont->text.wStringID = RS_OTA_BURNFLASH_DO_NOT_POWER_OFF;
			break;
		case PROC_SUCCESS:	
			src = OSD_GetUnicodeString(RS_DISPLAY_NEXT);
			ComUniStrCopyChar((UINT8*)len_display_str, src);
			str_len = ComUniStrLen(len_display_str);
			ComAscStr2Uni(" : ",&len_display_str[str_len]);
			str_len = ComUniStrLen(len_display_str);
			src = OSD_GetUnicodeString(RS_MSG_UPGRADE_REBOOT);
			ComUniStrCopyChar((UINT8*)&len_display_str[str_len], src);

			tcont->bTextType = STRING_UNICODE;
			tcont->text.pString = len_display_str;
			break;
		//case PROC_STOPPED:
		//	break;
		case PROC_FAILURE:
			tcont->text.wStringID = RS_MSG_UPGRADE_BURN_FLASH_FAIL;
			break;
		}
		
		
		break;
	}

	OSD_SetTextFieldContent(txt_btn, STRING_ID, (UINT32)btn_strid);

	if(update)
	{
		OSD_DrawObject((POBJECT_HEAD)mtxt_msg, C_UPDATE_ALL);
        apvscr = OSD_GetTaskVscr(osal_task_get_current_id());
        if(apvscr->lpbScr != NULL)
        {
            apvscr->updatePending = 1;
            OSD_UpdateVscr(apvscr);
        }		
		if(ota_proc_step == OTA_STEP_BURNFLASH && ota_proc_ret==0)
			OSD_DrawObject( (POBJECT_HEAD)txt_btn, C_UPDATE_ALL);
		else
			OSD_TrackObject((POBJECT_HEAD)txt_btn, C_UPDATE_ALL);
        apvscr = OSD_GetTaskVscr(osal_task_get_current_id());
        if(apvscr->lpbScr != NULL)
        {
            apvscr->updatePending = 1;
            OSD_UpdateVscr(apvscr);
        }
	}	
}

/* 0 - stop , 1 - exit , 2 - download 3 - burnflash 4 - reboot*/
INT32  win_otaup_get_btn_state(void)
{
	INT32 ret = 0;

	if(ota_proc_ret == PROC_SUCCESS)
		ret = 0;
	else if(ota_proc_ret == PROC_STOPPED)
		ret = 1;
	else if(ota_proc_ret == PROC_FAILURE)
		ret = 1;
	else
		ret = 0;

	switch(ota_proc_step)
	{
	case OTA_STEP_GET_INFO:
		if(ota_proc_ret == PROC_SUCCESS)
			ret = 2;
		break;
	case OTA_STEP_DOWNLOADING:	
		if(ota_proc_ret == PROC_SUCCESS)
			ret = 3;
		break;
	case OTA_STEP_BURNFLASH:
		if(ota_proc_ret == PROC_SUCCESS)
			ret = 4;
		else if(ota_proc_ret == 0)
			ret = 3;//5;
		break;		
	}

	return ret;

}

static void win_otaup_set_swinfo_display(BOOL update)
{
	MULTI_TEXT* mtxt_swinfo;
	TEXT_CONTENT* tcont;
	struct dl_info* info;
	char str[50];

	mtxt_swinfo = &otaupg_mtxt_swinfo;
	info = &ota_dl_info;

	tcont = &otasw_mtxt_content[0];
	tcont->text.pString = display_strs[10];

	tcont = &otasw_mtxt_content[1];
	tcont->text.pString = display_strs[11];

	tcont = &otasw_mtxt_content[2];
	tcont->text.pString = display_strs[12];


	if( (ota_proc_step== OTA_STEP_GET_INFO && ota_proc_ret == PROC_SUCCESS)
		|| ota_proc_step>OTA_STEP_GET_INFO)
	{
		tcont = &otasw_mtxt_content[0];
#if (defined(_CAS9_CA_ENABLE_) || defined(_VMX_CA_ENABLE_))
		sprintf(str,"	 H/W ver : %d.%d.%d.%d",
			(info->hw_version>>12) & 0xf,
			(info->hw_version>>8)  & 0xf,
			(info->hw_version>>4)  & 0xf,
			(info->hw_version>>0)  & 0xf);
#else
        sprintf(str,"    H/W ver : %d.%d",
            (info->hw_version>>4) & 0xfff,
            (info->hw_version>>0) & 0xf);	
#endif
		ComAscStr2Uni(str,tcont->text.pString);

		tcont = &otasw_mtxt_content[1];
#if (defined(_CAS9_CA_ENABLE_) || defined(_VMX_CA_ENABLE_))
		sprintf(str,"	 S/W ver : %d.%d.%d.%d",
			(info->sw_version>>12) & 0xf,
			(info->sw_version>>8)  & 0xf,
			(info->sw_version>>4)  & 0xf,
			(info->sw_version>>0)  & 0xf);
#else
        sprintf(str,"    S/W ver : %d.%d.%d",
            (info->sw_version>>8) & 0xff,
            (info->sw_version>>4) & 0xf,
            (info->sw_version>>0) & 0xf);
#endif
		ComAscStr2Uni(str,tcont->text.pString);

		tcont = &otasw_mtxt_content[2];
		sprintf(str,"    S/W size : %d bytes",info->sw_size);
		ComAscStr2Uni(str,tcont->text.pString);
	}
	else
	{
		tcont = &otasw_mtxt_content[0];
		ComAscStr2Uni("",tcont->text.pString);

		tcont = &otasw_mtxt_content[1];
		ComAscStr2Uni("",tcont->text.pString);

		tcont = &otasw_mtxt_content[2];
		ComAscStr2Uni("",tcont->text.pString);
	}

	if(update)
		OSD_DrawObject((POBJECT_HEAD)mtxt_swinfo, C_UPDATE_ALL);	
}


static void win_ota_upgrade_process_update_old(UINT32 process)
{
	PROGRESS_BAR* bar = &otaupg_progress_bar;
	TEXT_FIELD*  txt = &otaupg_progress_txt;
	TEXT_CONTENT tcont;
	MULTI_TEXT* mtxt_msg = &otaupg_mtxt_msg;
	UINT16 str_buf[50];
	char	progress_strs[30];
	lpVSCR apvscr;

#ifdef WATCH_DOG_SUPPORT
    dog_set_time(0, 0);
#endif
	tcont.text.pString = str_buf;
	tcont.bTextType = STRING_UNICODE;
	OSD_TaskBuffer_Init(osal_task_get_current_id(),NULL);
	if(process == OTA_START_BACKUP_FLAG)
	{
		ComAscStr2Uni("Start backup OTA data ...", str_buf);
		OSD_SetMultiTextContent(mtxt_msg, &tcont);
		OSD_DrawObject((POBJECT_HEAD)mtxt_msg, C_UPDATE_ALL);
		OSD_SetMultiTextContent(mtxt_msg, &otamsg_mtxt_content);
	}
	else if(process == OTA_START_END_FLAG)
	{
		OSD_SetMultiTextContent(mtxt_msg, &otamsg_mtxt_content);
		OSD_DrawObject((POBJECT_HEAD)mtxt_msg, C_UPDATE_ALL);
	}
	else
	{
		if(process > 100)
			process = 0;
	 
		OSD_SetProgressBarPos(bar,process);
		sprintf(progress_strs,"%d%%",process);
		OSD_SetTextFieldContent(txt,STRING_ANSI,(UINT32)progress_strs);

		OSD_DrawObject((POBJECT_HEAD)bar,C_UPDATE_ALL);
		OSD_DrawObject((POBJECT_HEAD)txt,C_UPDATE_ALL);	
	}
	apvscr = OSD_GetTaskVscr(osal_task_get_current_id());
    if(apvscr->lpbScr != NULL)
    {
        apvscr->updatePending = 1;
    }
	OSD_UpdateVscr(apvscr);	
}



static void win_ota_upgrade_process_update_ex(UINT32 process)
{
    static UINT32 old_process = 0;

    if(old_process == process)
        return;    
    ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_OTA_PROCESS_MSG,process,TRUE);
#ifdef WATCH_DOG_SUPPORT
    dog_set_time(0, 0);
#endif
    osal_task_sleep(1);
    old_process = process;
    //libc_printf("2 process:%d\n",process);
}

static void win_ota_upgrade_process_draw(UINT32 process)
{
	PROGRESS_BAR* bar = &otaupg_progress_bar;
	TEXT_FIELD*  txt = &otaupg_progress_txt;
	TEXT_CONTENT tcont;
	MULTI_TEXT* mtxt_msg = &otaupg_mtxt_msg;
	UINT16 str_buf[50];
	char	progress_strs[30];
	lpVSCR apvscr;

	tcont.text.pString = str_buf;
	tcont.bTextType = STRING_UNICODE;
	OSD_TaskBuffer_Init(osal_task_get_current_id(),NULL);
	if(process == OTA_START_BACKUP_FLAG)
	{
		ComAscStr2Uni("Start backup OTA data ...", str_buf);
		OSD_SetMultiTextContent(mtxt_msg, &tcont);
		OSD_DrawObject((POBJECT_HEAD)mtxt_msg, C_UPDATE_ALL);
		OSD_SetMultiTextContent(mtxt_msg, &otamsg_mtxt_content);
	}
	else if(process == OTA_START_END_FLAG)
	{
		OSD_SetMultiTextContent(mtxt_msg, &otamsg_mtxt_content);
		OSD_DrawObject((POBJECT_HEAD)mtxt_msg, C_UPDATE_ALL);
	}
	else
	{
		if(process > 100)
			process = 0;
//	    libc_printf("process:%d\n",process);
		OSD_SetProgressBarPos(bar,process);
		sprintf(progress_strs,"%d%%",process);
		OSD_SetTextFieldContent(txt,STRING_ANSI,(UINT32)progress_strs);

		OSD_DrawObject((POBJECT_HEAD)bar,C_UPDATE_ALL);
		OSD_DrawObject((POBJECT_HEAD)txt,C_UPDATE_ALL);	
	}
	apvscr = OSD_GetTaskVscr(osal_task_get_current_id());
    if(apvscr->lpbScr != NULL)
    {
        apvscr->updatePending = 1;
    }
	OSD_UpdateVscr(apvscr);	    
    
}


static void win_otaupg_init()
{
	PTEXT_FIELD pTxt;

	pTxt = &otaupg_progress_txt;
	OSD_SetTextFieldContent(pTxt,STRING_ANSI,(UINT32)"0%");
	PROGRESS_BAR* bar = &otaupg_progress_bar;
	OSD_SetProgressBarPos(bar,0);
}

#if defined(AUTO_OTA) && !defined(_BUILD_OTA_E_)
#if(defined(DVBT_SUPPORT)||defined(ISDBT_SUPPORT)||defined(DVBC_SUPPORT))
static BOOL get_OTA_parameter(POTA_PARAM param)
{
	union ssu_info ssu;
	
#if(defined(DVBT_SUPPORT)||defined(ISDBT_SUPPORT))
	si_get_ota_ssuinfo_t(&ssu);
	param->freq = ssu.t_ssuinfo.frequency;
	param->band = ssu.t_ssuinfo.bandwidth;
	param->pid = ssu.t_ssuinfo.ssu_pid;

	if ( param->freq == 0 )   //ota not found.
	{
		param->freq = 0;
		param->band = 0;
		param->pid = 0;
		return FALSE;
	}
#endif
#if(defined(DVBC_SUPPORT))
	si_get_ota_ssuinfo_c(&ssu);
	param->freq = ssu.c_ssuinfo.frequency;
	param->symbol = ssu.c_ssuinfo.symbol;
	param->qam = ssu.c_ssuinfo.qam;
	param->pid = ssu.c_ssuinfo.ssu_pid;
	
	if ( param->freq == 0 )   //ota not found.
	{
		param->freq = 0;
		param->symbol= 0;
		param->qam =0;
		param->pid = 0;
		return FALSE;
	}
#endif

    return TRUE;
}

static volatile INT8 ota_search_over = 0;
static void ota_detect_event(UINT8 aue_type, UINT32 aue_value)
{
	INT8 *p_is_stop = NULL;
	switch(aue_type)
	{
		case SI_OTA_VERSION_UPDATE:
			ota_search_over = 1;
			break;
		case SI_OTA_SEARCH_OVER:
			ota_search_over = 1;
			break;
		case SI_OTA_CHECK_STOPSEARCH_SIGNAL:
			p_is_stop= (INT8*)aue_value;
			*p_is_stop = 0; //ota_srch_stop
			break;
		default:
			break;
    }

}
extern Band_param uCountryParam[MAX_BAND_COUNT];
static void start_ota_detect()
{
	UINT32 i;
	struct as_service_param as_param;
	UINT8 uCurCountryIdx;
	SYSTEM_DATA *sys_data;

	ota_search_over = 0;

	MEMSET(&as_param, 0, sizeof(as_param));
	as_param.as_method = AS_METHOD_SSU_SEARCH;
	as_param.as_handler = ota_detect_event;
	sys_data = sys_data_get();
	
#if(defined(DVBT_SUPPORT)||defined(ISDBT_SUPPORT))

	as_param.as_frontend_type = FRONTEND_TYPE_T;
	//uCurCountryIdx = sys_data->region_id;
	uCurCountryIdx = sys_data->country;
#if(defined(ISDBT_SUPPORT))
	get_isdbt_bandparam(uCurCountryIdx, (Band_param *)&uCountryParam);
#elif(defined(DVBT_SUPPORT))
	get_dvbt_bandparam(uCurCountryIdx, (Band_param *)&uCountryParam);
#endif

#endif

#if(defined(DVBC_SUPPORT))
	as_param.as_frontend_type = FRONTEND_TYPE_C;
	if(sys_data->current_ft_count > 0)
    {
	    as_param.ft[0].c_param.sym= sys_data->current_ft[0].c_param.sym;
	    as_param.ft[0].c_param.constellation = sys_data->current_ft[0].c_param.constellation;
    }

	get_default_bandparam(sys_data->country, (Band_param *)&uCountryParam);

#endif

	as_param.band_group_param = uCountryParam;
#ifdef COMBOUI
	psi_set_search_ftype(as_param.as_frontend_type);
#endif
	for(i=0; i<MAX_BAND_COUNT; i++)
	{
		if(0 == uCountryParam[i].start_freq)
			break;
		else
			as_param.scan_cnt++;
	}
	as_service_start(&as_param);
}

#define OTA_SEARCH_OK				0
#define OTA_SEARCH_NOT_FOUND		-1
#define OTA_SEARCH_USER_CANCEL	-2
#define OTA_SEARCH_TIMER_WAKEUP	-3

BOOL m_ForFakeStandby = FALSE;
static int ota_auto_search(POTA_PARAM param,  date_time *wakeup_time)
{
	UINT32 hkey,vkey;
	unsigned long keycode;
	struct pan_key key_struct;
	int Result = OTA_SEARCH_NOT_FOUND;
	UINT32 addr, len;

    MEMSET(param, 0, sizeof(OTA_PARAM));


	addr = __MM_AUTOSCAN_DB_BUFFER_ADDR;
	addr &= 0x8fffffff;
	len = __MM_AUTOSCAN_DB_BUFFER_LEN;
	db_search_init((UINT8 *)addr, len);

 	extern BOOL ota_power_flag;
 	AUTO_OTA_PRINTF("start_ota_detect\n");
	start_ota_detect();
	while(!ota_search_over)
	{
		if(key_get_key(&key_struct,0))
		{
			keycode = scan_code_to_msg_code(&key_struct);
			ap_hk_to_vk(0, keycode, &vkey);
		}
		else
		{
			if(ota_power_flag)
			 {
			Result = OTA_SEARCH_USER_CANCEL;
			break;
		          }
		}

		if((vkey == V_KEY_POWER) ||
//               		(m_ForFakeStandby && (CTRL_MSG_SUBTYPE_KEY_FP == hkey)) ||
               		(!m_ForFakeStandby && (V_KEY_MENU == vkey || V_KEY_EXIT== vkey)))
		{
			Result = OTA_SEARCH_USER_CANCEL;
			break;
		}

		if(wakeup_time != NULL) //for check wake up timer
		{
			if(wakeup_time->year)
			{
				date_time dt;
				get_local_time(&dt);
				if(api_compare_day_time_ext(&dt,wakeup_time) >= 0) //auto wake up from standby.
				{
					Result = OTA_SEARCH_TIMER_WAKEUP;
					break;
				}
			}
//			UpdatePanelAsStandby();
		}
		else
		{
//			UpdateSearchingProgress();
		}
		osal_task_sleep(10);
//		ui_check_tuner();
//		ui_check_vcr();
	}
	if(ota_search_over) //lwj for ota debug
		{
			as_service_stop();
			db_search_exit();
		}

	if(!ota_search_over)
		as_otasearch_service_stop(!m_ForFakeStandby);
	else
		get_OTA_parameter(param);

	if(param->freq)
		Result = OTA_SEARCH_OK;

	return Result;
}

// TRUE: bootup right now; FALSE: enter passive standby
BOOL ota_stby_search(date_time *wakeup_time)
{
	BOOL flag_boot = FALSE;
	OTA_PARAM ota_param;
	date_time dt;

#ifdef ACTIVE_STANDBY
	m_ForFakeStandby = FALSE;
#else
	#ifdef NEW_MANUAL_OTA
   	extern  BOOL ota_set_menu;
   	if(ota_set_menu)
		m_ForFakeStandby = FALSE;
   	else
	#endif
	m_ForFakeStandby = TRUE;
#endif

/*
	if(!api_Scart_VCR_Detect()) //current status is STB
	{
		if(scart_com_vcr_detect())
		{
			ui_vcr_enable(TRUE);   //for active vcr switch by ui_check_vcr().
			scart_com_vcr_select(TRUE);
			ui_check_vcr_output(FALSE);
		}
	}
	ui_enable_vcr_detect(FALSE);
*/
	MEMCPY(&dt, wakeup_time, sizeof(date_time));

	int result = ota_auto_search(&ota_param, &dt);
	AUTO_OTA_PRINTF("ota_auto_search end:\
	result=%d\n",result);
	#ifdef NEW_MANUAL_OTA
   	if(ota_set_menu)
	{	
		UINT8 back_saved;
      	UINT32 msg_code;
		win_popup_choice_t choice;
		if(OTA_SEARCH_OK == result)
        {
      	 
	      	win_compopup_close();		
		  	win_compopup_smsg_restoreback(); 
		  	sys_data_set_ota_freq(ota_param.freq);
		  	sys_data_set_ota_band(ota_param.band);
		  	sys_data_set_ota_pid(ota_param.pid);
		  	sys_data_set_auto_ota_flag(1);
		  	sys_data_save(TRUE);
		  	osal_delay(40);
		  	win_compopup_init(WIN_POPUP_TYPE_OKNO);
		  	win_compopup_set_msg("Are you sure to upgrade the firmware?", NULL, 0);
		  	win_compopup_set_default_choice(WIN_POP_CHOICE_NO);
		  	choice = win_compopup_open_ext(&back_saved);
		  	if(choice == WIN_POP_CHOICE_YES)
		    {
			  	ap_send_msg(CTRL_MSG_SUBTYPE_CMD_OTA_INFORM, 0, FALSE);
			}
		  	else
		  	{
			   	ap_vk_to_hk(0, V_KEY_EXIT, &msg_code);
			   	ap_send_msg(CTRL_MSG_SUBTYPE_KEY, msg_code, FALSE);
		    }
        }
	  	else if((OTA_SEARCH_NOT_FOUND== result)||(OTA_SEARCH_USER_CANCEL== result))
		{		
	     	win_compopup_close();
			win_compopup_smsg_restoreback(); 
			win_compopup_init(WIN_POPUP_TYPE_OK);
		    win_compopup_set_msg("Can't find new firmware!", NULL, 0);
		  	choice = win_compopup_open_ext(&back_saved);
			//if(choice == WIN_POP_CHOICE_YES)
		    {
				//UINT32 msg_code; // construct virtual operation
				ap_vk_to_hk(0, V_KEY_EXIT, &msg_code);
				ap_send_msg(CTRL_MSG_SUBTYPE_KEY, msg_code, FALSE);
			}
		}
	}
	else
	#endif
	if(OTA_SEARCH_OK == result)
	{
#if (defined(DVBT_SUPPORT)||defined(ISDBT_SUPPORT))
        AUTO_OTA_PRINTF("OTA_SEARCH_OK:\
        freq=%d,band=%d,pid=%d\n",\
        ota_param.freq,ota_param.band,ota_param.pid);
		sys_data_set_ota_freq(ota_param.freq);
		sys_data_set_ota_band(ota_param.band);
		sys_data_set_ota_pid(ota_param.pid);
		sys_data_set_auto_ota_flag(1);
#endif	
#ifdef DVBC_SUPPORT
		sys_data_set_ota_freq(ota_param.freq);
		sys_data_set_ota_symbol(ota_param.symbol);
		sys_data_set_ota_pid(ota_param.pid);
		sys_data_set_ota_modulation(ota_param.qam);
#endif	

		sys_data_save(TRUE);
		osal_delay(40);
	}
	else if(OTA_SEARCH_USER_CANCEL == result)
	{
	    AUTO_OTA_PRINTF("OTA_SEARCH_USER_CANCEL\n");
		flag_boot = TRUE;
	}

    return flag_boot;
}
#endif
#endif
